1# -*- coding: utf-8 -*- 2from __future__ import absolute_import, unicode_literals 3import os 4import shutil 5import unittest 6import tempfile 7from io import open 8from fontTools.ufoLib import UFOReader, UFOWriter 9from fontTools.ufoLib import plistlib 10from .testSupport import expectedFontInfo1To2Conversion, expectedFontInfo2To1Conversion 11 12 13# the format version 1 lib.plist contains some data 14# that these tests shouldn't be concerned about. 15removeFromFormatVersion1Lib = [ 16 "org.robofab.opentype.classes", 17 "org.robofab.opentype.features", 18 "org.robofab.opentype.featureorder", 19 "org.robofab.postScriptHintData" 20] 21 22 23class ConversionFunctionsTestCase(unittest.TestCase): 24 25 def tearDown(self): 26 path = self.getFontPath("TestFont1 (UFO1) converted.ufo") 27 if os.path.exists(path): 28 shutil.rmtree(path) 29 path = self.getFontPath("TestFont1 (UFO2) converted.ufo") 30 if os.path.exists(path): 31 shutil.rmtree(path) 32 33 def getFontPath(self, fileName): 34 testdata = os.path.join(os.path.dirname(__file__), "testdata") 35 return os.path.join(testdata, fileName) 36 37 def compareFileStructures(self, path1, path2, expectedInfoData, testFeatures): 38 # result 39 metainfoPath1 = os.path.join(path1, "metainfo.plist") 40 fontinfoPath1 = os.path.join(path1, "fontinfo.plist") 41 kerningPath1 = os.path.join(path1, "kerning.plist") 42 groupsPath1 = os.path.join(path1, "groups.plist") 43 libPath1 = os.path.join(path1, "lib.plist") 44 featuresPath1 = os.path.join(path1, "features.plist") 45 glyphsPath1 = os.path.join(path1, "glyphs") 46 glyphsPath1_contents = os.path.join(glyphsPath1, "contents.plist") 47 glyphsPath1_A = os.path.join(glyphsPath1, "A_.glif") 48 glyphsPath1_B = os.path.join(glyphsPath1, "B_.glif") 49 # expected result 50 metainfoPath2 = os.path.join(path2, "metainfo.plist") 51 fontinfoPath2 = os.path.join(path2, "fontinfo.plist") 52 kerningPath2 = os.path.join(path2, "kerning.plist") 53 groupsPath2 = os.path.join(path2, "groups.plist") 54 libPath2 = os.path.join(path2, "lib.plist") 55 featuresPath2 = os.path.join(path2, "features.plist") 56 glyphsPath2 = os.path.join(path2, "glyphs") 57 glyphsPath2_contents = os.path.join(glyphsPath2, "contents.plist") 58 glyphsPath2_A = os.path.join(glyphsPath2, "A_.glif") 59 glyphsPath2_B = os.path.join(glyphsPath2, "B_.glif") 60 # look for existence 61 self.assertEqual(os.path.exists(metainfoPath1), True) 62 self.assertEqual(os.path.exists(fontinfoPath1), True) 63 self.assertEqual(os.path.exists(kerningPath1), True) 64 self.assertEqual(os.path.exists(groupsPath1), True) 65 self.assertEqual(os.path.exists(libPath1), True) 66 self.assertEqual(os.path.exists(glyphsPath1), True) 67 self.assertEqual(os.path.exists(glyphsPath1_contents), True) 68 self.assertEqual(os.path.exists(glyphsPath1_A), True) 69 self.assertEqual(os.path.exists(glyphsPath1_B), True) 70 if testFeatures: 71 self.assertEqual(os.path.exists(featuresPath1), True) 72 # look for aggrement 73 with open(metainfoPath1, "rb") as f: 74 data1 = plistlib.load(f) 75 with open(metainfoPath2, "rb") as f: 76 data2 = plistlib.load(f) 77 self.assertEqual(data1, data2) 78 with open(fontinfoPath1, "rb") as f: 79 data1 = plistlib.load(f) 80 self.assertEqual(sorted(data1.items()), sorted(expectedInfoData.items())) 81 with open(kerningPath1, "rb") as f: 82 data1 = plistlib.load(f) 83 with open(kerningPath2, "rb") as f: 84 data2 = plistlib.load(f) 85 self.assertEqual(data1, data2) 86 with open(groupsPath1, "rb") as f: 87 data1 = plistlib.load(f) 88 with open(groupsPath2, "rb") as f: 89 data2 = plistlib.load(f) 90 self.assertEqual(data1, data2) 91 with open(libPath1, "rb") as f: 92 data1 = plistlib.load(f) 93 with open(libPath2, "rb") as f: 94 data2 = plistlib.load(f) 95 if "UFO1" in libPath1: 96 for key in removeFromFormatVersion1Lib: 97 if key in data1: 98 del data1[key] 99 if "UFO1" in libPath2: 100 for key in removeFromFormatVersion1Lib: 101 if key in data2: 102 del data2[key] 103 self.assertEqual(data1, data2) 104 with open(glyphsPath1_contents, "rb") as f: 105 data1 = plistlib.load(f) 106 with open(glyphsPath2_contents, "rb") as f: 107 data2 = plistlib.load(f) 108 self.assertEqual(data1, data2) 109 with open(glyphsPath1_A, "rb") as f: 110 data1 = plistlib.load(f) 111 with open(glyphsPath2_A, "rb") as f: 112 data2 = plistlib.load(f) 113 self.assertEqual(data1, data2) 114 with open(glyphsPath1_B, "rb") as f: 115 data1 = plistlib.load(f) 116 with open(glyphsPath2_B, "rb") as f: 117 data2 = plistlib.load(f) 118 self.assertEqual(data1, data2) 119 120 121# --------------------- 122# kerning up conversion 123# --------------------- 124 125class TestInfoObject(object): pass 126 127 128class KerningUpConversionTestCase(unittest.TestCase): 129 130 expectedKerning = { 131 ("public.kern1.BGroup", "public.kern2.CGroup"): 7, 132 ("public.kern1.BGroup", "public.kern2.DGroup"): 8, 133 ("public.kern1.BGroup", "A"): 5, 134 ("public.kern1.BGroup", "B"): 6, 135 ("public.kern1.CGroup", "public.kern2.CGroup"): 11, 136 ("public.kern1.CGroup", "public.kern2.DGroup"): 12, 137 ("public.kern1.CGroup", "A"): 9, 138 ("public.kern1.CGroup", "B"): 10, 139 ("A", "public.kern2.CGroup"): 3, 140 ("A", "public.kern2.DGroup"): 4, 141 ("A", "A"): 1, 142 ("A", "B"): 2 143 } 144 145 expectedGroups = { 146 "BGroup": ["B"], 147 "CGroup": ["C", "Ccedilla"], 148 "DGroup": ["D"], 149 "public.kern1.BGroup": ["B"], 150 "public.kern1.CGroup": ["C", "Ccedilla"], 151 "public.kern2.CGroup": ["C", "Ccedilla"], 152 "public.kern2.DGroup": ["D"], 153 "Not A Kerning Group" : ["A"] 154 } 155 156 def setUp(self): 157 self.tempDir = tempfile.mktemp() 158 os.mkdir(self.tempDir) 159 self.ufoPath = os.path.join(self.tempDir, "test.ufo") 160 161 def tearDown(self): 162 shutil.rmtree(self.tempDir) 163 164 def makeUFO(self, formatVersion): 165 self.clearUFO() 166 if not os.path.exists(self.ufoPath): 167 os.mkdir(self.ufoPath) 168 # metainfo.plist 169 metaInfo = dict(creator="test", formatVersion=formatVersion) 170 path = os.path.join(self.ufoPath, "metainfo.plist") 171 with open(path, "wb") as f: 172 plistlib.dump(metaInfo, f) 173 # kerning 174 kerning = { 175 "A" : { 176 "A" : 1, 177 "B" : 2, 178 "CGroup" : 3, 179 "DGroup" : 4 180 }, 181 "BGroup" : { 182 "A" : 5, 183 "B" : 6, 184 "CGroup" : 7, 185 "DGroup" : 8 186 }, 187 "CGroup" : { 188 "A" : 9, 189 "B" : 10, 190 "CGroup" : 11, 191 "DGroup" : 12 192 } 193 } 194 path = os.path.join(self.ufoPath, "kerning.plist") 195 with open(path, "wb") as f: 196 plistlib.dump(kerning, f) 197 # groups 198 groups = { 199 "BGroup" : ["B"], 200 "CGroup" : ["C", "Ccedilla"], 201 "DGroup" : ["D"], 202 "Not A Kerning Group" : ["A"] 203 } 204 path = os.path.join(self.ufoPath, "groups.plist") 205 with open(path, "wb") as f: 206 plistlib.dump(groups, f) 207 # font info 208 fontInfo = { 209 "familyName" : "Test" 210 } 211 path = os.path.join(self.ufoPath, "fontinfo.plist") 212 with open(path, "wb") as f: 213 plistlib.dump(fontInfo, f) 214 215 def clearUFO(self): 216 if os.path.exists(self.ufoPath): 217 shutil.rmtree(self.ufoPath) 218 219 def testUFO1(self): 220 self.makeUFO(formatVersion=2) 221 reader = UFOReader(self.ufoPath, validate=True) 222 kerning = reader.readKerning() 223 self.assertEqual(self.expectedKerning, kerning) 224 groups = reader.readGroups() 225 self.assertEqual(self.expectedGroups, groups) 226 info = TestInfoObject() 227 reader.readInfo(info) 228 229 def testUFO2(self): 230 self.makeUFO(formatVersion=2) 231 reader = UFOReader(self.ufoPath, validate=True) 232 kerning = reader.readKerning() 233 self.assertEqual(self.expectedKerning, kerning) 234 groups = reader.readGroups() 235 self.assertEqual(self.expectedGroups, groups) 236 info = TestInfoObject() 237 reader.readInfo(info) 238 239 240class KerningDownConversionTestCase(unittest.TestCase): 241 242 expectedKerning = { 243 ("public.kern1.BGroup", "public.kern2.CGroup"): 7, 244 ("public.kern1.BGroup", "public.kern2.DGroup"): 8, 245 ("public.kern1.BGroup", "A"): 5, 246 ("public.kern1.BGroup", "B"): 6, 247 ("public.kern1.CGroup", "public.kern2.CGroup"): 11, 248 ("public.kern1.CGroup", "public.kern2.DGroup"): 12, 249 ("public.kern1.CGroup", "A"): 9, 250 ("public.kern1.CGroup", "B"): 10, 251 ("A", "public.kern2.CGroup"): 3, 252 ("A", "public.kern2.DGroup"): 4, 253 ("A", "A"): 1, 254 ("A", "B"): 2 255 } 256 257 groups = { 258 "BGroup": ["B"], 259 "CGroup": ["C"], 260 "DGroup": ["D"], 261 "public.kern1.BGroup": ["B"], 262 "public.kern1.CGroup": ["C", "Ccedilla"], 263 "public.kern2.CGroup": ["C", "Ccedilla"], 264 "public.kern2.DGroup": ["D"], 265 "Not A Kerning Group" : ["A"] 266 } 267 expectedWrittenGroups = { 268 "BGroup": ["B"], 269 "CGroup": ["C", "Ccedilla"], 270 "DGroup": ["D"], 271 "Not A Kerning Group" : ["A"] 272 } 273 274 kerning = { 275 ("public.kern1.BGroup", "public.kern2.CGroup"): 7, 276 ("public.kern1.BGroup", "public.kern2.DGroup"): 8, 277 ("public.kern1.BGroup", "A"): 5, 278 ("public.kern1.BGroup", "B"): 6, 279 ("public.kern1.CGroup", "public.kern2.CGroup"): 11, 280 ("public.kern1.CGroup", "public.kern2.DGroup"): 12, 281 ("public.kern1.CGroup", "A"): 9, 282 ("public.kern1.CGroup", "B"): 10, 283 ("A", "public.kern2.CGroup"): 3, 284 ("A", "public.kern2.DGroup"): 4, 285 ("A", "A"): 1, 286 ("A", "B"): 2 287 } 288 expectedWrittenKerning = { 289 "BGroup" : { 290 "CGroup" : 7, 291 "DGroup" : 8, 292 "A" : 5, 293 "B" : 6 294 }, 295 "CGroup" : { 296 "CGroup" : 11, 297 "DGroup" : 12, 298 "A" : 9, 299 "B" : 10 300 }, 301 "A" : { 302 "CGroup" : 3, 303 "DGroup" : 4, 304 "A" : 1, 305 "B" : 2 306 } 307 } 308 309 310 downConversionMapping = { 311 "side1" : { 312 "BGroup" : "public.kern1.BGroup", 313 "CGroup" : "public.kern1.CGroup" 314 }, 315 "side2" : { 316 "CGroup" : "public.kern2.CGroup", 317 "DGroup" : "public.kern2.DGroup" 318 } 319 } 320 321 def setUp(self): 322 self.tempDir = tempfile.mktemp() 323 os.mkdir(self.tempDir) 324 self.dstDir = os.path.join(self.tempDir, "test.ufo") 325 326 def tearDown(self): 327 shutil.rmtree(self.tempDir) 328 329 def tearDownUFO(self): 330 shutil.rmtree(self.dstDir) 331 332 def testWrite(self): 333 writer = UFOWriter(self.dstDir, formatVersion=2) 334 writer.setKerningGroupConversionRenameMaps(self.downConversionMapping) 335 writer.writeKerning(self.kerning) 336 writer.writeGroups(self.groups) 337 # test groups 338 path = os.path.join(self.dstDir, "groups.plist") 339 with open(path, "rb") as f: 340 writtenGroups = plistlib.load(f) 341 self.assertEqual(writtenGroups, self.expectedWrittenGroups) 342 # test kerning 343 path = os.path.join(self.dstDir, "kerning.plist") 344 with open(path, "rb") as f: 345 writtenKerning = plistlib.load(f) 346 self.assertEqual(writtenKerning, self.expectedWrittenKerning) 347 self.tearDownUFO() 348