import os
import shutil
import unittest
import tempfile
from io import open
from fontTools.ufoLib import UFOReader, UFOWriter, UFOLibError
from fontTools.ufoLib.glifLib import GlifLibError
from fontTools.misc import plistlib
from .testSupport import fontInfoVersion3


class TestInfoObject:
    pass


# --------------
# fontinfo.plist
# --------------


class ReadFontInfoVersion3TestCase(unittest.TestCase):
    def setUp(self):
        self.dstDir = tempfile.mktemp()
        os.mkdir(self.dstDir)
        metaInfo = {"creator": "test", "formatVersion": 3}
        path = os.path.join(self.dstDir, "metainfo.plist")
        with open(path, "wb") as f:
            plistlib.dump(metaInfo, f)

    def tearDown(self):
        shutil.rmtree(self.dstDir)

    def _writeInfoToPlist(self, info):
        path = os.path.join(self.dstDir, "fontinfo.plist")
        with open(path, "wb") as f:
            plistlib.dump(info, f)

    def testRead(self):
        originalData = dict(fontInfoVersion3)
        self._writeInfoToPlist(originalData)
        infoObject = TestInfoObject()
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(infoObject)
        readData = {}
        for attr in list(fontInfoVersion3.keys()):
            readData[attr] = getattr(infoObject, attr)
        self.assertEqual(originalData, readData)

    def testGenericRead(self):
        # familyName
        info = dict(fontInfoVersion3)
        info["familyName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # styleName
        info = dict(fontInfoVersion3)
        info["styleName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # styleMapFamilyName
        info = dict(fontInfoVersion3)
        info["styleMapFamilyName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # styleMapStyleName
        ## not a string
        info = dict(fontInfoVersion3)
        info["styleMapStyleName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out of range
        info = dict(fontInfoVersion3)
        info["styleMapStyleName"] = "REGULAR"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # versionMajor
        info = dict(fontInfoVersion3)
        info["versionMajor"] = "1"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # versionMinor
        info = dict(fontInfoVersion3)
        info["versionMinor"] = "0"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["versionMinor"] = -1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # copyright
        info = dict(fontInfoVersion3)
        info["copyright"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # trademark
        info = dict(fontInfoVersion3)
        info["trademark"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # unitsPerEm
        info = dict(fontInfoVersion3)
        info["unitsPerEm"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["unitsPerEm"] = -1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["unitsPerEm"] = -1.0
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # descender
        info = dict(fontInfoVersion3)
        info["descender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # xHeight
        info = dict(fontInfoVersion3)
        info["xHeight"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # capHeight
        info = dict(fontInfoVersion3)
        info["capHeight"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # ascender
        info = dict(fontInfoVersion3)
        info["ascender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # italicAngle
        info = dict(fontInfoVersion3)
        info["italicAngle"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())

    def testGaspRead(self):
        # not a list
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # empty list
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = []
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        # not a dict
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = ["abc"]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # dict not properly formatted
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [dict(rangeMaxPPEM=0xFFFF, notTheRightKey=1)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [
            dict(notTheRightKey=1, rangeGaspBehavior=[0])
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # not an int for ppem
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [
            dict(rangeMaxPPEM="abc", rangeGaspBehavior=[0]),
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # not a list for behavior
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [
            dict(rangeMaxPPEM=10, rangeGaspBehavior="abc"),
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # invalid behavior value
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [
            dict(rangeMaxPPEM=10, rangeGaspBehavior=[-1]),
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # not sorted
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # no 0xFFFF
        info = dict(fontInfoVersion3)
        info["openTypeGaspRangeRecords"] = [
            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
            dict(rangeMaxPPEM=20, rangeGaspBehavior=[0]),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())

    def testHeadRead(self):
        # openTypeHeadCreated
        ## not a string
        info = dict(fontInfoVersion3)
        info["openTypeHeadCreated"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## invalid format
        info = dict(fontInfoVersion3)
        info["openTypeHeadCreated"] = "2000-Jan-01 00:00:00"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHeadLowestRecPPEM
        info = dict(fontInfoVersion3)
        info["openTypeHeadLowestRecPPEM"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeHeadLowestRecPPEM"] = -1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHeadFlags
        info = dict(fontInfoVersion3)
        info["openTypeHeadFlags"] = [-1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())

    def testHheaRead(self):
        # openTypeHheaAscender
        info = dict(fontInfoVersion3)
        info["openTypeHheaAscender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHheaDescender
        info = dict(fontInfoVersion3)
        info["openTypeHheaDescender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHheaLineGap
        info = dict(fontInfoVersion3)
        info["openTypeHheaLineGap"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHheaCaretSlopeRise
        info = dict(fontInfoVersion3)
        info["openTypeHheaCaretSlopeRise"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHheaCaretSlopeRun
        info = dict(fontInfoVersion3)
        info["openTypeHheaCaretSlopeRun"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeHheaCaretOffset
        info = dict(fontInfoVersion3)
        info["openTypeHheaCaretOffset"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())

    def testNameRead(self):
        # openTypeNameDesigner
        info = dict(fontInfoVersion3)
        info["openTypeNameDesigner"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameDesignerURL
        info = dict(fontInfoVersion3)
        info["openTypeNameDesignerURL"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameManufacturer
        info = dict(fontInfoVersion3)
        info["openTypeNameManufacturer"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameManufacturerURL
        info = dict(fontInfoVersion3)
        info["openTypeNameManufacturerURL"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameLicense
        info = dict(fontInfoVersion3)
        info["openTypeNameLicense"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameLicenseURL
        info = dict(fontInfoVersion3)
        info["openTypeNameLicenseURL"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameVersion
        info = dict(fontInfoVersion3)
        info["openTypeNameVersion"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameUniqueID
        info = dict(fontInfoVersion3)
        info["openTypeNameUniqueID"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameDescription
        info = dict(fontInfoVersion3)
        info["openTypeNameDescription"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNamePreferredFamilyName
        info = dict(fontInfoVersion3)
        info["openTypeNamePreferredFamilyName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNamePreferredSubfamilyName
        info = dict(fontInfoVersion3)
        info["openTypeNamePreferredSubfamilyName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameCompatibleFullName
        info = dict(fontInfoVersion3)
        info["openTypeNameCompatibleFullName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameSampleText
        info = dict(fontInfoVersion3)
        info["openTypeNameSampleText"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameWWSFamilyName
        info = dict(fontInfoVersion3)
        info["openTypeNameWWSFamilyName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameWWSSubfamilyName
        info = dict(fontInfoVersion3)
        info["openTypeNameWWSSubfamilyName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeNameRecords
        ## not a list
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## not a dict
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = ["abc"]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## invalid dict structure
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [dict(foo="bar")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## incorrect keys
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
                foo="bar",
            )
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(platformID=1, encodingID=1, languageID=1, string="Name Record.")
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(nameID=1, encodingID=1, languageID=1, string="Name Record.")
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(nameID=1, platformID=1, languageID=1, string="Name Record.")
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(nameID=1, platformID=1, encodingID=1, string="Name Record.")
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(nameID=1, platformID=1, encodingID=1, languageID=1)
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## invalid values
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(
                nameID="1",
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
            )
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(
                nameID=1,
                platformID="1",
                encodingID=1,
                languageID=1,
                string="Name Record.",
            )
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(
                nameID=1,
                platformID=1,
                encodingID="1",
                languageID=1,
                string="Name Record.",
            )
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID="1",
                string="Name Record.",
            )
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(nameID=1, platformID=1, encodingID=1, languageID=1, string=1)
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## duplicate
        info = dict(fontInfoVersion3)
        info["openTypeNameRecords"] = [
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
            ),
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
            ),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())

    def testOS2Read(self):
        # openTypeOS2WidthClass
        ## not an int
        info = dict(fontInfoVersion3)
        info["openTypeOS2WidthClass"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out or range
        info = dict(fontInfoVersion3)
        info["openTypeOS2WidthClass"] = 15
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2WeightClass
        info = dict(fontInfoVersion3)
        ## not an int
        info["openTypeOS2WeightClass"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out of range
        info["openTypeOS2WeightClass"] = -50
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2Selection
        info = dict(fontInfoVersion3)
        info["openTypeOS2Selection"] = [-1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2VendorID
        info = dict(fontInfoVersion3)
        info["openTypeOS2VendorID"] = 1234
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2Panose
        ## not an int
        info = dict(fontInfoVersion3)
        info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, str(9)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## negative
        info = dict(fontInfoVersion3)
        info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, -9]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## too few values
        info = dict(fontInfoVersion3)
        info["openTypeOS2Panose"] = [0, 1, 2, 3]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2FamilyClass
        ## not an int
        info = dict(fontInfoVersion3)
        info["openTypeOS2FamilyClass"] = [1, str(1)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## too few values
        info = dict(fontInfoVersion3)
        info["openTypeOS2FamilyClass"] = [1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        info["openTypeOS2FamilyClass"] = [1, 1, 1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out of range
        info = dict(fontInfoVersion3)
        info["openTypeOS2FamilyClass"] = [1, 201]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2UnicodeRanges
        ## not an int
        info = dict(fontInfoVersion3)
        info["openTypeOS2UnicodeRanges"] = ["0"]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out of range
        info = dict(fontInfoVersion3)
        info["openTypeOS2UnicodeRanges"] = [-1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2CodePageRanges
        ## not an int
        info = dict(fontInfoVersion3)
        info["openTypeOS2CodePageRanges"] = ["0"]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out of range
        info = dict(fontInfoVersion3)
        info["openTypeOS2CodePageRanges"] = [-1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2TypoAscender
        info = dict(fontInfoVersion3)
        info["openTypeOS2TypoAscender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2TypoDescender
        info = dict(fontInfoVersion3)
        info["openTypeOS2TypoDescender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2TypoLineGap
        info = dict(fontInfoVersion3)
        info["openTypeOS2TypoLineGap"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2WinAscent
        info = dict(fontInfoVersion3)
        info["openTypeOS2WinAscent"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeOS2WinAscent"] = -1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2WinDescent
        info = dict(fontInfoVersion3)
        info["openTypeOS2WinDescent"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        info = dict(fontInfoVersion3)
        info["openTypeOS2WinDescent"] = -1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2Type
        ## not an int
        info = dict(fontInfoVersion3)
        info["openTypeOS2Type"] = ["1"]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        ## out of range
        info = dict(fontInfoVersion3)
        info["openTypeOS2Type"] = [-1]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SubscriptXSize
        info = dict(fontInfoVersion3)
        info["openTypeOS2SubscriptXSize"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SubscriptYSize
        info = dict(fontInfoVersion3)
        info["openTypeOS2SubscriptYSize"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SubscriptXOffset
        info = dict(fontInfoVersion3)
        info["openTypeOS2SubscriptXOffset"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SubscriptYOffset
        info = dict(fontInfoVersion3)
        info["openTypeOS2SubscriptYOffset"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SuperscriptXSize
        info = dict(fontInfoVersion3)
        info["openTypeOS2SuperscriptXSize"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SuperscriptYSize
        info = dict(fontInfoVersion3)
        info["openTypeOS2SuperscriptYSize"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SuperscriptXOffset
        info = dict(fontInfoVersion3)
        info["openTypeOS2SuperscriptXOffset"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2SuperscriptYOffset
        info = dict(fontInfoVersion3)
        info["openTypeOS2SuperscriptYOffset"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2StrikeoutSize
        info = dict(fontInfoVersion3)
        info["openTypeOS2StrikeoutSize"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeOS2StrikeoutPosition
        info = dict(fontInfoVersion3)
        info["openTypeOS2StrikeoutPosition"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())

    def testVheaRead(self):
        # openTypeVheaVertTypoAscender
        info = dict(fontInfoVersion3)
        info["openTypeVheaVertTypoAscender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeVheaVertTypoDescender
        info = dict(fontInfoVersion3)
        info["openTypeVheaVertTypoDescender"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeVheaVertTypoLineGap
        info = dict(fontInfoVersion3)
        info["openTypeVheaVertTypoLineGap"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeVheaCaretSlopeRise
        info = dict(fontInfoVersion3)
        info["openTypeVheaCaretSlopeRise"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeVheaCaretSlopeRun
        info = dict(fontInfoVersion3)
        info["openTypeVheaCaretSlopeRun"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # openTypeVheaCaretOffset
        info = dict(fontInfoVersion3)
        info["openTypeVheaCaretOffset"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())

    def testFONDRead(self):
        # macintoshFONDFamilyID
        info = dict(fontInfoVersion3)
        info["macintoshFONDFamilyID"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # macintoshFONDName
        info = dict(fontInfoVersion3)
        info["macintoshFONDName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())

    def testPostscriptRead(self):
        # postscriptFontName
        info = dict(fontInfoVersion3)
        info["postscriptFontName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # postscriptFullName
        info = dict(fontInfoVersion3)
        info["postscriptFullName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # postscriptSlantAngle
        info = dict(fontInfoVersion3)
        info["postscriptSlantAngle"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
        # postscriptUniqueID
        info = dict(fontInfoVersion3)
        info["postscriptUniqueID"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptUnderlineThickness
        info = dict(fontInfoVersion3)
        info["postscriptUnderlineThickness"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptUnderlinePosition
        info = dict(fontInfoVersion3)
        info["postscriptUnderlinePosition"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptIsFixedPitch
        info = dict(fontInfoVersion3)
        info["postscriptIsFixedPitch"] = 2
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptBlueValues
        ## not a list
        info = dict(fontInfoVersion3)
        info["postscriptBlueValues"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## uneven value count
        info = dict(fontInfoVersion3)
        info["postscriptBlueValues"] = [500]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        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, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptOtherBlues
        ## not a list
        info = dict(fontInfoVersion3)
        info["postscriptOtherBlues"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## uneven value count
        info = dict(fontInfoVersion3)
        info["postscriptOtherBlues"] = [500]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        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, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptFamilyBlues
        ## not a list
        info = dict(fontInfoVersion3)
        info["postscriptFamilyBlues"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## uneven value count
        info = dict(fontInfoVersion3)
        info["postscriptFamilyBlues"] = [500]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        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, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptFamilyOtherBlues
        ## not a list
        info = dict(fontInfoVersion3)
        info["postscriptFamilyOtherBlues"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## uneven value count
        info = dict(fontInfoVersion3)
        info["postscriptFamilyOtherBlues"] = [500]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        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, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptStemSnapH
        ## not list
        info = dict(fontInfoVersion3)
        info["postscriptStemSnapH"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        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, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptStemSnapV
        ## not list
        info = dict(fontInfoVersion3)
        info["postscriptStemSnapV"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many values
        info = dict(fontInfoVersion3)
        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, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptBlueFuzz
        info = dict(fontInfoVersion3)
        info["postscriptBlueFuzz"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptBlueShift
        info = dict(fontInfoVersion3)
        info["postscriptBlueShift"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptBlueScale
        info = dict(fontInfoVersion3)
        info["postscriptBlueScale"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptForceBold
        info = dict(fontInfoVersion3)
        info["postscriptForceBold"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptDefaultWidthX
        info = dict(fontInfoVersion3)
        info["postscriptDefaultWidthX"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptNominalWidthX
        info = dict(fontInfoVersion3)
        info["postscriptNominalWidthX"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptWeightName
        info = dict(fontInfoVersion3)
        info["postscriptWeightName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptDefaultCharacter
        info = dict(fontInfoVersion3)
        info["postscriptDefaultCharacter"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # postscriptWindowsCharacterSet
        info = dict(fontInfoVersion3)
        info["postscriptWindowsCharacterSet"] = -1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # macintoshFONDFamilyID
        info = dict(fontInfoVersion3)
        info["macintoshFONDFamilyID"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # macintoshFONDName
        info = dict(fontInfoVersion3)
        info["macintoshFONDName"] = 123
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())

    def testWOFFRead(self):
        # woffMajorVersion
        info = dict(fontInfoVersion3)
        info["woffMajorVersion"] = 1.0
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["woffMajorVersion"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMinorVersion
        info = dict(fontInfoVersion3)
        info["woffMinorVersion"] = 1.0
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["woffMinorVersion"] = "abc"
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMetadataUniqueID
        ## none
        info = dict(fontInfoVersion3)
        del info["woffMetadataUniqueID"]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## not a dict
        info = dict(fontInfoVersion3)
        info["woffMetadataUniqueID"] = 1
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## unknown key
        info = dict(fontInfoVersion3)
        info["woffMetadataUniqueID"] = dict(id="foo", notTheRightKey=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no id
        info = dict(fontInfoVersion3)
        info["woffMetadataUniqueID"] = dict()
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## not a string for id
        info = dict(fontInfoVersion3)
        info["woffMetadataUniqueID"] = dict(id=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## empty string
        info = dict(fontInfoVersion3)
        info["woffMetadataUniqueID"] = dict(id="")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        # woffMetadataVendor
        ## no name
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(url="foo")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## name not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name=1, url="foo")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## name an empty string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="", url="foo")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## no URL
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo", url=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## url empty string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo", url="")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## have dir
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir="ltr")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir="rtl")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## dir not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir="utd")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## have class
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = {"name": "foo", "url": "bar", "class": "hello"}
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = {"name": "foo", "url": "bar", "class": 1}
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## class empty string
        info = dict(fontInfoVersion3)
        info["woffMetadataVendor"] = {"name": "foo", "url": "bar", "class": ""}
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        # woffMetadataCredits
        ## no credits attribute
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = {}
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## unknown attribute
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name="foo")], notTheRightKey=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## not a list
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits="abc")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no elements in credits
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## credit not a dict
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=["abc"])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## unknown key
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", notTheRightKey=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no name
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(url="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## name not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", url=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## role not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", role=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", dir=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", dir="utd")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCredits"] = dict(credits=[{"name": "foo", "class": 1}])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMetadataDescription
        ## no url
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(text="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(text="foo")], url=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no text
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(url="foo")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a list
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text="abc")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item not a dict
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=["abc"])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item unknown key
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(
            text=[dict(text="foo", notTheRightKey=1)]
        )
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item missing text
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(language="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(text=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(text="foo", url=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## language not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(text="foo", language=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[dict(text="foo", dir="utd")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataDescription"] = dict(text=[{"text": "foo", "class": 1}])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMetadataLicense
        ## no url
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo")], url=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## id not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo")], id=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no text
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(url="foo")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## text not a list
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text="abc")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item not a dict
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=["abc"])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item unknown key
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo", notTheRightKey=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item missing text
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(language="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo", url=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## language not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo", language=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[dict(text="foo", dir="utd")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicense"] = dict(text=[{"text": "foo", "class": 1}])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMetadataCopyright
        ## unknown attribute
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(text="foo")], notTheRightKey=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no text
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict()
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a list
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text="abc")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item not a dict
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=["abc"])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item unknown key
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", notTheRightKey=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item missing text
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(language="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(text=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", url=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## language not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", language=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", dir="utd")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataCopyright"] = dict(text=[{"text": "foo", "class": 1}])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMetadataTrademark
        ## unknown attribute
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(text="foo")], notTheRightKey=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## no text
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict()
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a list
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text="abc")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item not a dict
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=["abc"])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item unknown key
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", notTheRightKey=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text item missing text
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(language="foo")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## text not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(text=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## url not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", url=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## language not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", language=1)])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", dir="utd")])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataTrademark"] = dict(text=[{"text": "foo", "class": 1}])
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # woffMetadataLicensee
        ## no name
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = dict()
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## unknown attribute
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = dict(name="foo", notTheRightKey=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## name not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = dict(name=1)
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## dir options
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = dict(name="foo", dir="ltr")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = dict(name="foo", dir="rtl")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## dir not ltr or rtl
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = dict(name="foo", dir="utd")
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## have class
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = {"name": "foo", "class": "hello"}
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        reader.readInfo(TestInfoObject())
        ## class not a string
        info = dict(fontInfoVersion3)
        info["woffMetadataLicensee"] = {"name": "foo", "class": 1}
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())

    def testGuidelinesRead(self):
        # x
        ## not an int or float
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x="1")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # y
        ## not an int or float
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(y="1")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # angle
        ## < 0
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, y=0, angle=-1)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## > 360
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, y=0, angle=361)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # name
        ## not a string
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, name=1)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # color
        ## not a string
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color=1)]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## not enough commas
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1 0, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1 0 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1 0 0 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## not enough parts
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color=", 0, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, , 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, 0, , 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, 0, 0, ")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color=", , , ")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## not a number in all positions
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="r, 1, 1, 1")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, g, 1, 1")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, 1, b, 1")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, 1, 1, a")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## too many parts
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="1, 0, 0, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## < 0 in each position
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="-1, 0, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="0, -1, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="0, 0, -1, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="0, 0, 0, -1")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        ## > 1 in each position
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="2, 0, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="0, 2, 0, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="0, 0, 2, 0")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        info = dict(fontInfoVersion3)
        info["guidelines"] = [dict(x=0, color="0, 0, 0, 2")]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
        # identifier
        ## duplicate
        info = dict(fontInfoVersion3)
        info["guidelines"] = [
            dict(x=0, identifier="guide1"),
            dict(y=0, identifier="guide1"),
        ]
        self._writeInfoToPlist(info)
        reader = UFOReader(self.dstDir, validate=True)
        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())


class WriteFontInfoVersion3TestCase(unittest.TestCase):
    def setUp(self):
        self.tempDir = tempfile.mktemp()
        os.mkdir(self.tempDir)
        self.dstDir = os.path.join(self.tempDir, "test.ufo")

    def tearDown(self):
        shutil.rmtree(self.tempDir)

    def tearDownUFO(self):
        if os.path.exists(self.dstDir):
            shutil.rmtree(self.dstDir)

    def makeInfoObject(self):
        infoObject = TestInfoObject()
        for attr, value in list(fontInfoVersion3.items()):
            setattr(infoObject, attr, value)
        return infoObject

    def readPlist(self):
        path = os.path.join(self.dstDir, "fontinfo.plist")
        with open(path, "rb") as f:
            plist = plistlib.load(f)
        return plist

    def testWrite(self):
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        writtenData = self.readPlist()
        for attr, originalValue in list(fontInfoVersion3.items()):
            newValue = writtenData[attr]
            self.assertEqual(newValue, originalValue)
        self.tearDownUFO()

    def testGenericWrite(self):
        # familyName
        infoObject = self.makeInfoObject()
        infoObject.familyName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # styleName
        infoObject = self.makeInfoObject()
        infoObject.styleName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # styleMapFamilyName
        infoObject = self.makeInfoObject()
        infoObject.styleMapFamilyName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # styleMapStyleName
        ## not a string
        infoObject = self.makeInfoObject()
        infoObject.styleMapStyleName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out of range
        infoObject = self.makeInfoObject()
        infoObject.styleMapStyleName = "REGULAR"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # versionMajor
        infoObject = self.makeInfoObject()
        infoObject.versionMajor = "1"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # versionMinor
        infoObject = self.makeInfoObject()
        infoObject.versionMinor = "0"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # copyright
        infoObject = self.makeInfoObject()
        infoObject.copyright = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # trademark
        infoObject = self.makeInfoObject()
        infoObject.trademark = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # unitsPerEm
        infoObject = self.makeInfoObject()
        infoObject.unitsPerEm = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # descender
        infoObject = self.makeInfoObject()
        infoObject.descender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # xHeight
        infoObject = self.makeInfoObject()
        infoObject.xHeight = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # capHeight
        infoObject = self.makeInfoObject()
        infoObject.capHeight = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # ascender
        infoObject = self.makeInfoObject()
        infoObject.ascender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # italicAngle
        infoObject = self.makeInfoObject()
        infoObject.italicAngle = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testGaspWrite(self):
        # not a list
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # empty list
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = []
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        # not a dict
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = ["abc"]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # dict not properly formatted
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(rangeMaxPPEM=0xFFFF, notTheRightKey=1)
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(notTheRightKey=1, rangeGaspBehavior=[0])
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # not an int for ppem
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(rangeMaxPPEM="abc", rangeGaspBehavior=[0]),
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # not a list for behavior
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(rangeMaxPPEM=10, rangeGaspBehavior="abc"),
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # invalid behavior value
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(rangeMaxPPEM=10, rangeGaspBehavior=[-1]),
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # not sorted
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # no 0xFFFF
        infoObject = self.makeInfoObject()
        infoObject.openTypeGaspRangeRecords = [
            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
            dict(rangeMaxPPEM=20, rangeGaspBehavior=[0]),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()

    def testHeadWrite(self):
        # openTypeHeadCreated
        ## not a string
        infoObject = self.makeInfoObject()
        infoObject.openTypeHeadCreated = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## invalid format
        infoObject = self.makeInfoObject()
        infoObject.openTypeHeadCreated = "2000-Jan-01 00:00:00"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHeadLowestRecPPEM
        infoObject = self.makeInfoObject()
        infoObject.openTypeHeadLowestRecPPEM = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHeadFlags
        infoObject = self.makeInfoObject()
        infoObject.openTypeHeadFlags = [-1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testHheaWrite(self):
        # openTypeHheaAscender
        infoObject = self.makeInfoObject()
        infoObject.openTypeHheaAscender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHheaDescender
        infoObject = self.makeInfoObject()
        infoObject.openTypeHheaDescender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHheaLineGap
        infoObject = self.makeInfoObject()
        infoObject.openTypeHheaLineGap = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHheaCaretSlopeRise
        infoObject = self.makeInfoObject()
        infoObject.openTypeHheaCaretSlopeRise = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHheaCaretSlopeRun
        infoObject = self.makeInfoObject()
        infoObject.openTypeHheaCaretSlopeRun = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeHheaCaretOffset
        infoObject = self.makeInfoObject()
        infoObject.openTypeHheaCaretOffset = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testNameWrite(self):
        # openTypeNameDesigner
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameDesigner = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameDesignerURL
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameDesignerURL = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameManufacturer
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameManufacturer = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameManufacturerURL
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameManufacturerURL = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameLicense
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameLicense = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameLicenseURL
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameLicenseURL = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameVersion
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameVersion = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameUniqueID
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameUniqueID = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameDescription
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameDescription = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNamePreferredFamilyName
        infoObject = self.makeInfoObject()
        infoObject.openTypeNamePreferredFamilyName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNamePreferredSubfamilyName
        infoObject = self.makeInfoObject()
        infoObject.openTypeNamePreferredSubfamilyName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameCompatibleFullName
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameCompatibleFullName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameSampleText
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameSampleText = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameWWSFamilyName
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameWWSFamilyName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameWWSSubfamilyName
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameWWSSubfamilyName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeNameRecords
        ## not a list
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## not a dict
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = ["abc"]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## invalid dict structure
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [dict(foo="bar")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## incorrect keys
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
                foo="bar",
            )
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(platformID=1, encodingID=1, languageID=1, string="Name Record.")
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(nameID=1, encodingID=1, languageID=1, string="Name Record.")
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(nameID=1, platformID=1, languageID=1, string="Name Record.")
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(nameID=1, platformID=1, encodingID=1, string="Name Record.")
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(nameID=1, platformID=1, encodingID=1, languageID=1)
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## invalid values
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(
                nameID="1",
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
            )
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(
                nameID=1,
                platformID="1",
                encodingID=1,
                languageID=1,
                string="Name Record.",
            )
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(
                nameID=1,
                platformID=1,
                encodingID="1",
                languageID=1,
                string="Name Record.",
            )
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID="1",
                string="Name Record.",
            )
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(nameID=1, platformID=1, encodingID=1, languageID=1, string=1)
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## duplicate
        infoObject = self.makeInfoObject()
        infoObject.openTypeNameRecords = [
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
            ),
            dict(
                nameID=1,
                platformID=1,
                encodingID=1,
                languageID=1,
                string="Name Record.",
            ),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)

    def testOS2Write(self):
        # openTypeOS2WidthClass
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WidthClass = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out or range
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WidthClass = 15
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2WeightClass
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WeightClass = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out of range
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WeightClass = -50
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2Selection
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2Selection = [-1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2VendorID
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2VendorID = 1234
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2Panose
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2Panose = [0, 1, 2, 3, 4, 5, 6, 7, 8, str(9)]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## too few values
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2Panose = [0, 1, 2, 3]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## too many values
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2Panose = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2FamilyClass
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2FamilyClass = [0, str(1)]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## too few values
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2FamilyClass = [1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## too many values
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2FamilyClass = [1, 1, 1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out of range
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2FamilyClass = [1, 20]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2UnicodeRanges
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2UnicodeRanges = ["0"]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out of range
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2UnicodeRanges = [-1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2CodePageRanges
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2CodePageRanges = ["0"]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out of range
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2CodePageRanges = [-1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2TypoAscender
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2TypoAscender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2TypoDescender
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2TypoDescender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2TypoLineGap
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2TypoLineGap = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2WinAscent
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WinAscent = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WinAscent = -1
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2WinDescent
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WinDescent = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2WinDescent = -1
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2Type
        ## not an int
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2Type = ["1"]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## out of range
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2Type = [-1]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SubscriptXSize
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SubscriptXSize = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SubscriptYSize
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SubscriptYSize = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SubscriptXOffset
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SubscriptXOffset = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SubscriptYOffset
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SubscriptYOffset = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SuperscriptXSize
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SuperscriptXSize = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SuperscriptYSize
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SuperscriptYSize = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SuperscriptXOffset
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SuperscriptXOffset = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2SuperscriptYOffset
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2SuperscriptYOffset = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2StrikeoutSize
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2StrikeoutSize = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeOS2StrikeoutPosition
        infoObject = self.makeInfoObject()
        infoObject.openTypeOS2StrikeoutPosition = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testVheaWrite(self):
        # openTypeVheaVertTypoAscender
        infoObject = self.makeInfoObject()
        infoObject.openTypeVheaVertTypoAscender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeVheaVertTypoDescender
        infoObject = self.makeInfoObject()
        infoObject.openTypeVheaVertTypoDescender = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeVheaVertTypoLineGap
        infoObject = self.makeInfoObject()
        infoObject.openTypeVheaVertTypoLineGap = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeVheaCaretSlopeRise
        infoObject = self.makeInfoObject()
        infoObject.openTypeVheaCaretSlopeRise = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeVheaCaretSlopeRun
        infoObject = self.makeInfoObject()
        infoObject.openTypeVheaCaretSlopeRun = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # openTypeVheaCaretOffset
        infoObject = self.makeInfoObject()
        infoObject.openTypeVheaCaretOffset = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testFONDWrite(self):
        # macintoshFONDFamilyID
        infoObject = self.makeInfoObject()
        infoObject.macintoshFONDFamilyID = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # macintoshFONDName
        infoObject = self.makeInfoObject()
        infoObject.macintoshFONDName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testPostscriptWrite(self):
        # postscriptFontName
        infoObject = self.makeInfoObject()
        infoObject.postscriptFontName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptFullName
        infoObject = self.makeInfoObject()
        infoObject.postscriptFullName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptSlantAngle
        infoObject = self.makeInfoObject()
        infoObject.postscriptSlantAngle = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptUniqueID
        infoObject = self.makeInfoObject()
        infoObject.postscriptUniqueID = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptUnderlineThickness
        infoObject = self.makeInfoObject()
        infoObject.postscriptUnderlineThickness = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptUnderlinePosition
        infoObject = self.makeInfoObject()
        infoObject.postscriptUnderlinePosition = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptIsFixedPitch
        infoObject = self.makeInfoObject()
        infoObject.postscriptIsFixedPitch = 2
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptBlueValues
        ## not a list
        infoObject = self.makeInfoObject()
        infoObject.postscriptBlueValues = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## uneven value count
        infoObject = self.makeInfoObject()
        infoObject.postscriptBlueValues = [500]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## 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, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptOtherBlues
        ## not a list
        infoObject = self.makeInfoObject()
        infoObject.postscriptOtherBlues = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## uneven value count
        infoObject = self.makeInfoObject()
        infoObject.postscriptOtherBlues = [500]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## 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, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptFamilyBlues
        ## not a list
        infoObject = self.makeInfoObject()
        infoObject.postscriptFamilyBlues = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## uneven value count
        infoObject = self.makeInfoObject()
        infoObject.postscriptFamilyBlues = [500]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## 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, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptFamilyOtherBlues
        ## not a list
        infoObject = self.makeInfoObject()
        infoObject.postscriptFamilyOtherBlues = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## uneven value count
        infoObject = self.makeInfoObject()
        infoObject.postscriptFamilyOtherBlues = [500]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## 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, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptStemSnapH
        ## not list
        infoObject = self.makeInfoObject()
        infoObject.postscriptStemSnapH = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## 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, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptStemSnapV
        ## not list
        infoObject = self.makeInfoObject()
        infoObject.postscriptStemSnapV = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## 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, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptBlueFuzz
        infoObject = self.makeInfoObject()
        infoObject.postscriptBlueFuzz = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptBlueShift
        infoObject = self.makeInfoObject()
        infoObject.postscriptBlueShift = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptBlueScale
        infoObject = self.makeInfoObject()
        infoObject.postscriptBlueScale = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptForceBold
        infoObject = self.makeInfoObject()
        infoObject.postscriptForceBold = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptDefaultWidthX
        infoObject = self.makeInfoObject()
        infoObject.postscriptDefaultWidthX = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptNominalWidthX
        infoObject = self.makeInfoObject()
        infoObject.postscriptNominalWidthX = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptWeightName
        infoObject = self.makeInfoObject()
        infoObject.postscriptWeightName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptDefaultCharacter
        infoObject = self.makeInfoObject()
        infoObject.postscriptDefaultCharacter = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # postscriptWindowsCharacterSet
        infoObject = self.makeInfoObject()
        infoObject.postscriptWindowsCharacterSet = -1
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # macintoshFONDFamilyID
        infoObject = self.makeInfoObject()
        infoObject.macintoshFONDFamilyID = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # macintoshFONDName
        infoObject = self.makeInfoObject()
        infoObject.macintoshFONDName = 123
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testWOFFWrite(self):
        # woffMajorVersion
        infoObject = self.makeInfoObject()
        infoObject.woffMajorVersion = 1.0
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.woffMajorVersion = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMinorVersion
        infoObject = self.makeInfoObject()
        infoObject.woffMinorVersion = 1.0
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.woffMinorVersion = "abc"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMetadataUniqueID
        ## none
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataUniqueID = None
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## not a dict
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataUniqueID = 1
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## unknown key
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataUniqueID = dict(id="foo", notTheRightKey=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no id
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataUniqueID = dict()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## not a string for id
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataUniqueID = dict(id=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## empty string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataUniqueID = dict(id="")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        # woffMetadataVendor
        ## no name
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(url="foo")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## name not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name=1, url="foo")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## name an empty string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="", url="foo")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## no URL
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo", url=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## url empty string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo", url="")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## have dir
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir="ltr")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir="rtl")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## dir not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir="utd")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## have class
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = {"name": "foo", "url": "bar", "class": "hello"}
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = {"name": "foo", "url": "bar", "class": 1}
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## class empty string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataVendor = {"name": "foo", "url": "bar", "class": ""}
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        # woffMetadataCredits
        ## no credits attribute
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = {}
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## unknown attribute
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(
            credits=[dict(name="foo")], notTheRightKey=1
        )
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## not a list
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits="abc")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no elements in credits
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## credit not a dict
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=["abc"])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## unknown key
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(
            credits=[dict(name="foo", notTheRightKey=1)]
        )
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no name
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[dict(url="foo")])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## name not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[dict(name=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", url=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## role not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", role=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", dir=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", dir="utd")])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCredits = dict(credits=[{"name": "foo", "class": 1}])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMetadataDescription
        ## no url
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(text="foo")])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(text="foo")], url=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no text
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(url="foo")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a list
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text="abc")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item not a dict
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=["abc"])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item unknown key
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(
            text=[dict(text="foo", notTheRightKey=1)]
        )
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item missing text
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(language="foo")])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(text=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(text="foo", url=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## language not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(text="foo", language=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[dict(text="foo", dir="utd")])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataDescription = dict(text=[{"text": "foo", "class": 1}])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMetadataLicense
        ## no url
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo")])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo")], url=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## id not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo")], id=1)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no text
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(url="foo")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## text not a list
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(text="abc")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item not a dict
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(text=["abc"])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item unknown key
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", notTheRightKey=1)])
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item missing text
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicense = dict(text=[dict(language="foo")])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicense = dict(text=[dict(text=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", url=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## language not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", language=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", dir="utd")])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicense = dict(text=[{"text": "foo", "class": 1}])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMetadataCopyright
        ## unknown attribute
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(
            text=[dict(text="foo")], notTheRightKey=1
        )
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no text
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict()
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a list
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text="abc")
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item not a dict
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text=["abc"])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item unknown key
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(
            text=[dict(text="foo", notTheRightKey=1)]
        )
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item missing text
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataCopyright = dict(text=[dict(language="foo")])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text=[dict(text=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text=[dict(text="foo", url=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## language not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text=[dict(text="foo", language=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text=[dict(text="foo", dir="utd")])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataCopyright = dict(text=[{"text": "foo", "class": 1}])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMetadataTrademark
        ## unknown attribute
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(
            text=[dict(text="foo")], notTheRightKey=1
        )
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## no text
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict()
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a list
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text="abc")
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item not a dict
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=["abc"])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item unknown key
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(
            text=[dict(text="foo", notTheRightKey=1)]
        )
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text item missing text
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=[dict(language="foo")])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## text not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=[dict(text=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## url not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=[dict(text="foo", url=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## language not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=[dict(text="foo", language=1)])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=[dict(text="foo", dir="utd")])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataTrademark = dict(text=[{"text": "foo", "class": 1}])
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # woffMetadataLicensee
        ## no name
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicensee = dict()
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## unknown attribute
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicensee = dict(name="foo", notTheRightKey=1)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## name not a string
        infoObject = self.makeInfoObject()
        writer = UFOWriter(self.dstDir, formatVersion=3)
        infoObject.woffMetadataLicensee = dict(name=1)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## dir options
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicensee = dict(name="foo", dir="ltr")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicensee = dict(name="foo", dir="rtl")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## dir not ltr or rtl
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicensee = dict(name="foo", dir="utd")
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## have class
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicensee = {"name": "foo", "class": "hello"}
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeInfo(infoObject)
        self.tearDownUFO()
        ## class not a string
        infoObject = self.makeInfoObject()
        infoObject.woffMetadataLicensee = {"name": "foo", "class": 1}
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()

    def testGuidelinesWrite(self):
        # x
        ## not an int or float
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x="1")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # y
        ## not an int or float
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(y="1")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # angle
        ## < 0
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, y=0, angle=-1)]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## > 360
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, y=0, angle=361)]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # name
        ## not a string
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, name=1)]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # color
        ## not a string
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color=1)]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## not enough commas
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1 0, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1 0 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1 0 0 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## not enough parts
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color=", 0, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, , 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, 0, , 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, 0, 0, ")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color=", , , ")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## not a number in all positions
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="r, 1, 1, 1")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, g, 1, 1")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, 1, b, 1")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, 1, 1, a")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## too many parts
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="1, 0, 0, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## < 0 in each position
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="-1, 0, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="0, -1, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="0, 0, -1, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="0, 0, 0, -1")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## > 1 in each position
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="2, 0, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="0, 2, 0, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="0, 0, 2, 0")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, color="0, 0, 0, 2")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        # identifier
        ## duplicate
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [
            dict(x=0, identifier="guide1"),
            dict(y=0, identifier="guide1"),
        ]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## below min
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, identifier="\0x1F")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()
        ## above max
        infoObject = self.makeInfoObject()
        infoObject.guidelines = [dict(x=0, identifier="\0x7F")]
        writer = UFOWriter(self.dstDir, formatVersion=3)
        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
        self.tearDownUFO()


# ------
# layers
# ------


class UFO3ReadLayersTestCase(unittest.TestCase):
    def setUp(self):
        self.tempDir = tempfile.mktemp()
        os.mkdir(self.tempDir)
        self.ufoPath = os.path.join(self.tempDir, "test.ufo")

    def tearDown(self):
        shutil.rmtree(self.tempDir)

    def makeUFO(self, metaInfo=None, layerContents=None):
        self.clearUFO()
        if not os.path.exists(self.ufoPath):
            os.mkdir(self.ufoPath)
        # metainfo.plist
        if metaInfo is None:
            metaInfo = dict(creator="test", formatVersion=3)
        path = os.path.join(self.ufoPath, "metainfo.plist")
        with open(path, "wb") as f:
            plistlib.dump(metaInfo, f)
        # layers
        if layerContents is None:
            layerContents = [
                ("public.default", "glyphs"),
                ("layer 1", "glyphs.layer 1"),
                ("layer 2", "glyphs.layer 2"),
            ]
        if layerContents:
            path = os.path.join(self.ufoPath, "layercontents.plist")
            with open(path, "wb") as f:
                plistlib.dump(layerContents, f)
        else:
            layerContents = [("", "glyphs")]
        for name, directory in layerContents:
            glyphsPath = os.path.join(self.ufoPath, directory)
            os.mkdir(glyphsPath)
            contents = dict(a="a.glif")
            path = os.path.join(glyphsPath, "contents.plist")
            with open(path, "wb") as f:
                plistlib.dump(contents, f)
            path = os.path.join(glyphsPath, "a.glif")
            with open(path, "w") as f:
                f.write(" ")

    def clearUFO(self):
        if os.path.exists(self.ufoPath):
            shutil.rmtree(self.ufoPath)

    # valid

    def testValidRead(self):
        # UFO 1
        self.makeUFO(
            metaInfo=dict(creator="test", formatVersion=1), layerContents=dict()
        )
        reader = UFOReader(self.ufoPath, validate=True)
        reader.getGlyphSet()
        # UFO 2
        self.makeUFO(
            metaInfo=dict(creator="test", formatVersion=2), layerContents=dict()
        )
        reader = UFOReader(self.ufoPath, validate=True)
        reader.getGlyphSet()
        # UFO 3
        self.makeUFO()
        reader = UFOReader(self.ufoPath, validate=True)
        reader.getGlyphSet()

    # missing layer contents

    def testMissingLayerContents(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # layer contents invalid format

    def testInvalidLayerContentsFormat(self):
        # bogus
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        with open(path, "w") as f:
            f.write("test")
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)
        # dict
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = {
            "public.default": "glyphs",
            "layer 1": "glyphs.layer 1",
            "layer 2": "glyphs.layer 2",
        }
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # layer contents invalid name format

    def testInvalidLayerContentsNameFormat(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            (1, "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # layer contents invalid directory format

    def testInvalidLayerContentsDirectoryFormat(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", 1),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # directory listed in contents not on disk

    def testLayerContentsHasMissingDirectory(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.doesnotexist"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # # directory on disk not listed in contents
    # XXX should this raise an error?
    #
    # def testLayerContentsHasMissingDirectory(self):
    # 	self.makeUFO()
    # 	path = os.path.join(self.ufoPath, "layercontents.plist")
    # 	os.remove(path)
    # 	layerContents = [
    # 		("public.foregound", "glyphs"),
    # 		("layer 1", "glyphs.layer 2")
    # 	]
    # 	with open(path, "wb") as f:
    # 		plistlib.dump(layerContents, f)
    # 	reader = UFOReader(self.ufoPath, validate=True)
    # 	with self.assertRaises(UFOLibError):
    # 		reader.getGlyphSet()

    # no default layer on disk

    def testMissingDefaultLayer(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [("layer 1", "glyphs.layer 1"), ("layer 2", "glyphs.layer 2")]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # duplicate layer name

    def testDuplicateLayerName(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 1", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # directory referenced by two layer names

    def testDuplicateLayerDirectory(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 1"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        self.assertRaises(UFOLibError, reader.getGlyphSet)

    # default without a name

    def testDefaultLayerNoName(self):
        # get the glyph set
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        reader.getGlyphSet()

    # default with a name

    def testDefaultLayerName(self):
        # get the name
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("custom name", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        expected = layerContents[0][0]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        result = reader.getDefaultLayerName()
        self.assertEqual(expected, result)
        # get the glyph set
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("custom name", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        reader.getGlyphSet(expected)

    # layer order

    def testLayerOrder(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        expected = [name for (name, directory) in layerContents]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        result = reader.getLayerNames()
        self.assertEqual(expected, result)
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("layer 1", "glyphs.layer 1"),
            ("public.foregound", "glyphs"),
            ("layer 2", "glyphs.layer 2"),
        ]
        expected = [name for (name, directory) in layerContents]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        result = reader.getLayerNames()
        self.assertEqual(expected, result)
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("layer 2", "glyphs.layer 2"),
            ("layer 1", "glyphs.layer 1"),
            ("public.foregound", "glyphs"),
        ]
        expected = [name for (name, directory) in layerContents]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        reader = UFOReader(self.ufoPath, validate=True)
        result = reader.getLayerNames()
        self.assertEqual(expected, result)


class UFO3WriteLayersTestCase(unittest.TestCase):
    def setUp(self):
        self.tempDir = tempfile.mktemp()
        os.mkdir(self.tempDir)
        self.ufoPath = os.path.join(self.tempDir, "test.ufo")

    def tearDown(self):
        shutil.rmtree(self.tempDir)

    def makeUFO(self, metaInfo=None, layerContents=None):
        self.clearUFO()
        if not os.path.exists(self.ufoPath):
            os.mkdir(self.ufoPath)
        # metainfo.plist
        if metaInfo is None:
            metaInfo = dict(creator="test", formatVersion=3)
        path = os.path.join(self.ufoPath, "metainfo.plist")
        with open(path, "wb") as f:
            plistlib.dump(metaInfo, f)
        # layers
        if layerContents is None:
            layerContents = [
                ("public.default", "glyphs"),
                ("layer 1", "glyphs.layer 1"),
                ("layer 2", "glyphs.layer 2"),
            ]
        if layerContents:
            path = os.path.join(self.ufoPath, "layercontents.plist")
            with open(path, "wb") as f:
                plistlib.dump(layerContents, f)
        else:
            layerContents = [("", "glyphs")]
        for name, directory in layerContents:
            glyphsPath = os.path.join(self.ufoPath, directory)
            os.mkdir(glyphsPath)
            contents = dict(a="a.glif")
            path = os.path.join(glyphsPath, "contents.plist")
            with open(path, "wb") as f:
                plistlib.dump(contents, f)
            path = os.path.join(glyphsPath, "a.glif")
            with open(path, "w") as f:
                f.write(" ")

    def clearUFO(self):
        if os.path.exists(self.ufoPath):
            shutil.rmtree(self.ufoPath)

    # __init__: missing layer contents

    def testMissingLayerContents(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: layer contents invalid format

    def testInvalidLayerContentsFormat(self):
        # bogus
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        with open(path, "w") as f:
            f.write("test")
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
        # dict
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = {
            "public.default": "glyphs",
            "layer 1": "glyphs.layer 1",
            "layer 2": "glyphs.layer 2",
        }
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: layer contents invalid name format

    def testInvalidLayerContentsNameFormat(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            (1, "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: layer contents invalid directory format

    def testInvalidLayerContentsDirectoryFormat(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", 1),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: directory listed in contents not on disk

    def testLayerContentsHasMissingDirectory(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.doesnotexist"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: no default layer on disk

    def testMissingDefaultLayer(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [("layer 1", "glyphs.layer 1"), ("layer 2", "glyphs.layer 2")]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: duplicate layer name

    def testDuplicateLayerName(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 1", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: directory referenced by two layer names

    def testDuplicateLayerDirectory(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 1"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)

    # __init__: default without a name

    def testDefaultLayerNoName(self):
        # get the glyph set
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("public.foregound", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        writer = UFOWriter(self.ufoPath)

    # __init__: default with a name

    def testDefaultLayerName(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "layercontents.plist")
        os.remove(path)
        layerContents = [
            ("custom name", "glyphs"),
            ("layer 1", "glyphs.layer 1"),
            ("layer 2", "glyphs.layer 2"),
        ]
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        writer = UFOWriter(self.ufoPath)

    # __init__: up convert 1 > 3

    def testUpConvert1To3(self):
        self.makeUFO(
            metaInfo=dict(creator="test", formatVersion=1), layerContents=dict()
        )
        writer = UFOWriter(self.ufoPath)
        writer.writeLayerContents(["public.default"])
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [["public.default", "glyphs"]]
        self.assertEqual(expected, result)

    # __init__: up convert 2 > 3

    def testUpConvert2To3(self):
        self.makeUFO(
            metaInfo=dict(creator="test", formatVersion=2), layerContents=dict()
        )
        writer = UFOWriter(self.ufoPath)
        writer.writeLayerContents(["public.default"])
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [["public.default", "glyphs"]]
        self.assertEqual(expected, result)

    # __init__: down convert 3 > 1

    def testDownConvert3To1(self):
        self.makeUFO()
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath, formatVersion=1)

    # __init__: down convert 3 > 2

    def testDownConvert3To2(self):
        self.makeUFO()
        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath, formatVersion=2)

    # get glyph sets

    def testGetGlyphSets(self):
        self.makeUFO()
        # hack contents.plist
        path = os.path.join(self.ufoPath, "glyphs.layer 1", "contents.plist")
        with open(path, "wb") as f:
            plistlib.dump(dict(b="a.glif"), f)
        path = os.path.join(self.ufoPath, "glyphs.layer 2", "contents.plist")
        with open(path, "wb") as f:
            plistlib.dump(dict(c="a.glif"), f)
        # now test
        writer = UFOWriter(self.ufoPath)
        # default
        expected = ["a"]
        result = list(writer.getGlyphSet().keys())
        self.assertEqual(expected, result)
        # layer 1
        expected = ["b"]
        result = list(writer.getGlyphSet("layer 1", defaultLayer=False).keys())
        self.assertEqual(expected, result)
        # layer 2
        expected = ["c"]
        result = list(writer.getGlyphSet("layer 2", defaultLayer=False).keys())
        self.assertEqual(expected, result)

    def testGetGlyphSetNoContents(self):
        self.makeUFO()
        os.remove(os.path.join(self.ufoPath, "glyphs.layer 1", "contents.plist"))

        reader = UFOReader(self.ufoPath, validate=True)
        with self.assertRaises(GlifLibError):
            reader.getGlyphSet("layer 1")

        writer = UFOWriter(self.ufoPath, validate=True)
        with self.assertRaises(GlifLibError):
            writer.getGlyphSet("layer 1", defaultLayer=False, expectContentsFile=True)

        # There's a separate code path for < v3 UFOs.
        with open(os.path.join(self.ufoPath, "metainfo.plist"), "wb") as f:
            plistlib.dump(dict(creator="test", formatVersion=2), f)
        os.remove(os.path.join(self.ufoPath, "glyphs", "contents.plist"))
        writer = UFOWriter(self.ufoPath, validate=True, formatVersion=2)
        with self.assertRaises(GlifLibError):
            writer.getGlyphSet(expectContentsFile=True)

    # make a new font with two layers

    def testNewFontOneLayer(self):
        self.clearUFO()
        writer = UFOWriter(self.ufoPath)
        writer.getGlyphSet()
        writer.writeLayerContents(["public.default"])
        # directory
        path = os.path.join(self.ufoPath, "glyphs")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [["public.default", "glyphs"]]
        self.assertEqual(expected, result)

    def testNewFontThreeLayers(self):
        self.clearUFO()
        writer = UFOWriter(self.ufoPath)
        writer.getGlyphSet("layer 1", defaultLayer=False)
        writer.getGlyphSet()
        writer.getGlyphSet("layer 2", defaultLayer=False)
        writer.writeLayerContents(["layer 1", "public.default", "layer 2"])
        # directories
        path = os.path.join(self.ufoPath, "glyphs")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 1")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 2")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [
            ["layer 1", "glyphs.layer 1"],
            ["public.default", "glyphs"],
            ["layer 2", "glyphs.layer 2"],
        ]
        self.assertEqual(expected, result)

    # add a layer to an existing font

    def testAddLayerToExistingFont(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        writer.getGlyphSet("layer 3", defaultLayer=False)
        writer.writeLayerContents(["public.default", "layer 1", "layer 2", "layer 3"])
        # directories
        path = os.path.join(self.ufoPath, "glyphs")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 1")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 2")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 3")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [
            ["public.default", "glyphs"],
            ["layer 1", "glyphs.layer 1"],
            ["layer 2", "glyphs.layer 2"],
            ["layer 3", "glyphs.layer 3"],
        ]
        self.assertEqual(expected, result)

    # rename valid name

    def testRenameLayer(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        writer.renameGlyphSet("layer 1", "layer 3")
        writer.writeLayerContents(["public.default", "layer 3", "layer 2"])
        # directories
        path = os.path.join(self.ufoPath, "glyphs")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 1")
        exists = os.path.exists(path)
        self.assertEqual(False, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 2")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 3")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [
            ["public.default", "glyphs"],
            ["layer 3", "glyphs.layer 3"],
            ["layer 2", "glyphs.layer 2"],
        ]
        self.assertEqual(expected, result)

    def testRenameLayerDefault(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        writer.renameGlyphSet("public.default", "layer xxx")
        writer.renameGlyphSet("layer 1", "layer 1", defaultLayer=True)
        writer.writeLayerContents(["layer xxx", "layer 1", "layer 2"])
        path = os.path.join(self.ufoPath, "glyphs")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 1")
        exists = os.path.exists(path)
        self.assertEqual(False, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 2")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer xxx")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [
            ["layer xxx", "glyphs.layer xxx"],
            ["layer 1", "glyphs"],
            ["layer 2", "glyphs.layer 2"],
        ]
        self.assertEqual(expected, result)

    # rename duplicate name

    def testRenameLayerDuplicateName(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        self.assertRaises(UFOLibError, writer.renameGlyphSet, "layer 1", "layer 2")

    # rename unknown layer

    def testRenameLayerUnknownName(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        self.assertRaises(
            UFOLibError, writer.renameGlyphSet, "does not exist", "layer 2"
        )

    # remove valid layer

    def testRemoveLayer(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        writer.deleteGlyphSet("layer 1")
        writer.writeLayerContents(["public.default", "layer 2"])
        # directories
        path = os.path.join(self.ufoPath, "glyphs")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 1")
        exists = os.path.exists(path)
        self.assertEqual(False, exists)
        path = os.path.join(self.ufoPath, "glyphs.layer 2")
        exists = os.path.exists(path)
        self.assertEqual(True, exists)
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [["public.default", "glyphs"], ["layer 2", "glyphs.layer 2"]]
        self.assertEqual(expected, result)

    # remove default layer

    def testRemoveDefaultLayer(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        writer.deleteGlyphSet("public.default")
        writer.writeLayerContents(["layer 1", "layer 2"])
        # directories
        path = os.path.join(self.ufoPath, "glyphs")
        self.assertEqual(False, os.path.exists(path))
        path = os.path.join(self.ufoPath, "glyphs.layer 1")
        self.assertEqual(True, os.path.exists(path))
        path = os.path.join(self.ufoPath, "glyphs.layer 2")
        self.assertEqual(True, os.path.exists(path))
        # layer contents
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [["layer 1", "glyphs.layer 1"], ["layer 2", "glyphs.layer 2"]]
        self.assertEqual(expected, result)

    # remove unknown layer

    def testRemoveDefaultLayer2(self):
        self.makeUFO()
        writer = UFOWriter(self.ufoPath)
        self.assertRaises(UFOLibError, writer.deleteGlyphSet, "does not exist")

    def testWriteAsciiLayerOrder(self):
        self.makeUFO(
            layerContents=[
                ["public.default", "glyphs"],
                ["layer 1", "glyphs.layer 1"],
                ["layer 2", "glyphs.layer 2"],
            ]
        )
        writer = UFOWriter(self.ufoPath)
        writer.writeLayerContents(["public.default", "layer 2", "layer 1"])
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        expected = [
            ["public.default", "glyphs"],
            ["layer 2", "glyphs.layer 2"],
            ["layer 1", "glyphs.layer 1"],
        ]
        self.assertEqual(expected, result)
        for layerName, _ in result:
            assert isinstance(layerName, str)


# -----
# /data
# -----


class UFO3ReadDataTestCase(unittest.TestCase):
    def getFontPath(self):
        testdata = os.path.join(os.path.dirname(__file__), "testdata")
        return os.path.join(testdata, "UFO3-Read Data.ufo")

    def testUFOReaderDataDirectoryListing(self):
        reader = UFOReader(self.getFontPath())
        found = reader.getDataDirectoryListing()
        expected = [
            "org.unifiedfontobject.directory/bar/lol.txt",
            "org.unifiedfontobject.directory/foo.txt",
            "org.unifiedfontobject.file.txt",
        ]
        self.assertEqual(set(found), set(expected))

    def testUFOReaderBytesFromPath(self):
        reader = UFOReader(self.getFontPath())
        found = reader.readBytesFromPath("data/org.unifiedfontobject.file.txt")
        expected = b"file.txt"
        self.assertEqual(found, expected)
        found = reader.readBytesFromPath(
            "data/org.unifiedfontobject.directory/bar/lol.txt"
        )
        expected = b"lol.txt"
        self.assertEqual(found, expected)
        found = reader.readBytesFromPath("data/org.unifiedfontobject.doesNotExist")
        expected = None
        self.assertEqual(found, expected)

    def testUFOReaderReadFileFromPath(self):
        reader = UFOReader(self.getFontPath())
        fileObject = reader.getReadFileForPath("data/org.unifiedfontobject.file.txt")
        self.assertNotEqual(fileObject, None)
        hasRead = hasattr(fileObject, "read")
        self.assertEqual(hasRead, True)
        fileObject.close()
        fileObject = reader.getReadFileForPath(
            "data/org.unifiedfontobject.doesNotExist"
        )
        self.assertEqual(fileObject, None)

    def testUFOReaderKernGroupDuplicatesRemoved(self):
        # Non-kerning group duplicates are kept
        # Kerning group duplicates are removed
        expected_groups = {
            "group1": ["A"],
            "group2": ["B", "C", "B"],
            "public.kern1.A": ["A"],
            "public.kern2.B": ["B", "A", "C"],
        }
        reader = UFOReader(self.getFontPath())
        groups = reader.readGroups()
        self.assertEqual(expected_groups, groups)


class UFO3WriteDataTestCase(unittest.TestCase):
    def setUp(self):
        self.tempDir = tempfile.mktemp()
        os.mkdir(self.tempDir)
        self.dstDir = os.path.join(self.tempDir, "test.ufo")

    def tearDown(self):
        shutil.rmtree(self.tempDir)

    def tearDownUFO(self):
        if os.path.exists(self.dstDir):
            shutil.rmtree(self.dstDir)

    def testUFOWriterWriteBytesToPath(self):
        # basic file
        path = "data/org.unifiedfontobject.writebytesbasicfile.txt"
        testBytes = b"test"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeBytesToPath(path, testBytes)
        path = os.path.join(self.dstDir, path)
        self.assertEqual(os.path.exists(path), True)
        with open(path, "rb") as f:
            written = f.read()
        self.assertEqual(testBytes, written)
        self.tearDownUFO()
        # basic file with unicode text
        path = "data/org.unifiedfontobject.writebytesbasicunicodefile.txt"
        text = b"t\xeb\xdft"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeBytesToPath(path, text)
        path = os.path.join(self.dstDir, path)
        self.assertEqual(os.path.exists(path), True)
        with open(path, "rb") as f:
            written = f.read()
        self.assertEqual(text, written)
        self.tearDownUFO()
        # basic directory
        path = "data/org.unifiedfontobject.writebytesdirectory/level1/level2/file.txt"
        testBytes = b"test"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeBytesToPath(path, testBytes)
        path = os.path.join(self.dstDir, path)
        self.assertEqual(os.path.exists(path), True)
        with open(path, "rb") as f:
            written = f.read()
        self.assertEqual(testBytes, written)
        self.tearDownUFO()

    def testUFOWriterWriteFileToPath(self):
        # basic file
        path = "data/org.unifiedfontobject.getwritefile.txt"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        fileObject = writer.getFileObjectForPath(path)
        self.assertNotEqual(fileObject, None)
        hasRead = hasattr(fileObject, "read")
        self.assertEqual(hasRead, True)
        fileObject.close()
        self.tearDownUFO()

    def testUFOWriterRemoveFile(self):
        path1 = "data/org.unifiedfontobject.removefile/level1/level2/file1.txt"
        path2 = "data/org.unifiedfontobject.removefile/level1/level2/file2.txt"
        path3 = "data/org.unifiedfontobject.removefile/level1/file3.txt"
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.writeBytesToPath(path1, b"test")
        writer.writeBytesToPath(path2, b"test")
        writer.writeBytesToPath(path3, b"test")
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path1)), True)
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path2)), True)
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), True)
        writer.removeFileForPath(path1)
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path1)), False)
        self.assertEqual(
            os.path.exists(os.path.dirname(os.path.join(self.dstDir, path1))), True
        )
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path2)), True)
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), True)
        writer.removeFileForPath(path2)
        self.assertEqual(
            os.path.exists(os.path.dirname(os.path.join(self.dstDir, path1))), False
        )
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path2)), False)
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), True)
        writer.removeFileForPath(path3)
        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), False)
        self.assertEqual(
            os.path.exists(os.path.dirname(os.path.join(self.dstDir, path2))), False
        )
        self.assertEqual(
            os.path.exists(
                os.path.join(self.dstDir, "data/org.unifiedfontobject.removefile")
            ),
            False,
        )
        self.assertRaises(
            UFOLibError,
            writer.removeFileForPath,
            path="data/org.unifiedfontobject.doesNotExist.txt",
        )
        self.tearDownUFO()

    def testUFOWriterCopy(self):
        sourceDir = self.dstDir.replace(".ufo", "") + "-copy source" + ".ufo"
        dataPath = "data/org.unifiedfontobject.copy/level1/level2/file1.txt"
        writer = UFOWriter(sourceDir, formatVersion=3)
        writer.writeBytesToPath(dataPath, b"test")
        # copy a file
        reader = UFOReader(sourceDir)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        writer.copyFromReader(reader, dataPath, dataPath)
        path = os.path.join(self.dstDir, dataPath)
        self.assertEqual(os.path.exists(path), True)
        self.tearDownUFO()
        # copy a directory
        reader = UFOReader(sourceDir)
        writer = UFOWriter(self.dstDir, formatVersion=3)
        p = "data/org.unifiedfontobject.copy"
        writer.copyFromReader(reader, p, p)
        path = os.path.join(self.dstDir, dataPath)
        self.assertEqual(os.path.exists(path), True)
        self.tearDownUFO()


# ---------------
# layerinfo.plist
# ---------------


class TestLayerInfoObject:
    color = guidelines = lib = None


class UFO3ReadLayerInfoTestCase(unittest.TestCase):
    def setUp(self):
        self.tempDir = tempfile.mktemp()
        os.mkdir(self.tempDir)
        self.ufoPath = os.path.join(self.tempDir, "test.ufo")

    def tearDown(self):
        shutil.rmtree(self.tempDir)

    def makeUFO(self, formatVersion=3, layerInfo=None):
        self.clearUFO()
        if not os.path.exists(self.ufoPath):
            os.mkdir(self.ufoPath)
        # metainfo.plist
        metaInfo = dict(creator="test", formatVersion=formatVersion)
        path = os.path.join(self.ufoPath, "metainfo.plist")
        with open(path, "wb") as f:
            plistlib.dump(metaInfo, f)
        # layercontents.plist
        layerContents = [("public.default", "glyphs")]
        path = os.path.join(self.ufoPath, "layercontents.plist")
        with open(path, "wb") as f:
            plistlib.dump(layerContents, f)
        # glyphs
        glyphsPath = os.path.join(self.ufoPath, "glyphs")
        os.mkdir(glyphsPath)
        contents = dict(a="a.glif")
        path = os.path.join(glyphsPath, "contents.plist")
        with open(path, "wb") as f:
            plistlib.dump(contents, f)
        path = os.path.join(glyphsPath, "a.glif")
        with open(path, "w") as f:
            f.write(" ")
        # layerinfo.plist
        if layerInfo is None:
            layerInfo = dict(color="0,0,0,1", lib={"foo": "bar"})
        path = os.path.join(glyphsPath, "layerinfo.plist")
        with open(path, "wb") as f:
            plistlib.dump(layerInfo, f)

    def clearUFO(self):
        if os.path.exists(self.ufoPath):
            shutil.rmtree(self.ufoPath)

    def testValidLayerInfo(self):
        self.makeUFO()
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        info = TestLayerInfoObject()
        glyphSet.readLayerInfo(info)
        expectedColor = "0,0,0,1"
        self.assertEqual(expectedColor, info.color)
        expectedLib = {"foo": "bar"}
        self.assertEqual(expectedLib, info.lib)

    def testMissingLayerInfo(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
        os.remove(path)
        # read
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        info = TestLayerInfoObject()
        glyphSet.readLayerInfo(info)
        self.assertEqual(None, info.color)
        self.assertEqual(None, info.guidelines)
        self.assertEqual(None, info.lib)

    def testBogusLayerInfo(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
        os.remove(path)
        with open(path, "w") as f:
            f.write("test")
        # read
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        info = TestLayerInfoObject()
        self.assertRaises(UFOLibError, glyphSet.readLayerInfo, info)

    def testInvalidFormatLayerInfo(self):
        self.makeUFO()
        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
        info = [("color", "0,0,0,0")]
        with open(path, "wb") as f:
            plistlib.dump(info, f)
        # read
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        info = TestLayerInfoObject()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, info)

    def testColor(self):
        ## not a string
        info = {}
        info["color"] = 1
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        ## not enough commas
        info = {}
        info["color"] = "1 0, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1 0 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1 0 0 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        ## not enough parts
        info = {}
        info["color"] = ", 0, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1, , 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1, 0, , 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1, 0, 0, "
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = ", , , "
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        ## not a number in all positions
        info = {}
        info["color"] = "r, 1, 1, 1"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1, g, 1, 1"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1, 1, b, 1"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "1, 1, 1, a"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        ## too many parts
        info = {}
        info["color"] = "1, 0, 0, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        ## < 0 in each position
        info = {}
        info["color"] = "-1, 0, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "0, -1, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "0, 0, -1, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "0, 0, 0, -1"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        ## > 1 in each position
        info = {}
        info["color"] = "2, 0, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "0, 2, 0, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "0, 0, 2, 0"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
        info = {}
        info["color"] = "0, 0, 0, 2"
        self.makeUFO(layerInfo=info)
        reader = UFOReader(self.ufoPath, validate=True)
        glyphSet = reader.getGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())


class UFO3WriteLayerInfoTestCase(unittest.TestCase):
    def setUp(self):
        self.tempDir = tempfile.mktemp()
        os.mkdir(self.tempDir)
        self.ufoPath = os.path.join(self.tempDir, "test.ufo")

    def tearDown(self):
        shutil.rmtree(self.tempDir)

    def makeGlyphSet(self):
        self.clearUFO()
        writer = UFOWriter(self.ufoPath)
        return writer.getGlyphSet()

    def clearUFO(self):
        if os.path.exists(self.ufoPath):
            shutil.rmtree(self.ufoPath)

    def testValidWrite(self):
        expected = dict(color="0,0,0,1", lib={"foo": "bar"})
        info = TestLayerInfoObject()
        info.color = expected["color"]
        info.lib = expected["lib"]
        glyphSet = self.makeGlyphSet()
        glyphSet.writeLayerInfo(info)
        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
        with open(path, "rb") as f:
            result = plistlib.load(f)
        self.assertEqual(expected, result)

    def testColor(self):
        ## not a string
        info = TestLayerInfoObject()
        info.color = 1
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        ## not enough commas
        info = TestLayerInfoObject()
        info.color = "1 0, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1 0 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1 0 0 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        ## not enough parts
        info = TestLayerInfoObject()
        info.color = ", 0, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1, , 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1, 0, , 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1, 0, 0, "
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = ", , , "
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        ## not a number in all positions
        info = TestLayerInfoObject()
        info.color = "r, 1, 1, 1"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1, g, 1, 1"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1, 1, b, 1"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "1, 1, 1, a"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        ## too many parts
        info = TestLayerInfoObject()
        info.color = "1, 0, 0, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        ## < 0 in each position
        info = TestLayerInfoObject()
        info.color = "-1, 0, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "0, -1, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "0, 0, -1, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "0, 0, 0, -1"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        ## > 1 in each position
        info = TestLayerInfoObject()
        info.color = "2, 0, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "0, 2, 0, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "0, 0, 2, 0"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
        info = TestLayerInfoObject()
        info.color = "0, 0, 0, 2"
        glyphSet = self.makeGlyphSet()
        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
