def test_family_name_custom(self): font = generate_minimal_font() instances_list = [{ 'name': 'Regular1' }, { 'name': 'Regular2', 'customParameters': [ { 'name': 'familyName', 'value': 'CustomFamily' }, ] }] font.instances = [ generate_instance_from_dict(i) for i in instances_list ] ufos, instance_data = to_ufos(font, include_instances=True, family_name='CustomFamily') instances = instance_data['data'] # only instances with familyName='CustomFamily' are included self.assertEqual(len(instances), 1) self.assertEqual(instances[0].name, 'Regular2') self.assertEqual(len(instances[0].customParameters), 1) self.assertEqual(instances[0].customParameters[0].value, 'CustomFamily') # the masters' family is also modified to use custom 'family_name' for ufo in ufos: self.assertEqual(ufo.info.familyName, 'CustomFamily')
def test_family_name_none(self): font = generate_minimal_font() instances_list = [{ 'name': 'Regular1' }, { 'name': 'Regular2', 'customParameters': [ { 'name': 'familyName', 'value': 'CustomFamily' }, ] }] font.instances = [ generate_instance_from_dict(i) for i in instances_list ] # 'family_name' defaults to None ufos, instance_data = to_ufos(font, include_instances=True) instances = instance_data['data'] # all instances are included, both with/without 'familyName' parameter self.assertEqual(len(instances), 2) self.assertEqual(instances[0].name, 'Regular1') self.assertEqual(instances[1].name, 'Regular2') self.assertEqual(len(instances[0].customParameters), 0) self.assertEqual(len(instances[1].customParameters), 1) self.assertEqual(instances[1].customParameters[0].value, 'CustomFamily') # the masters' family name is unchanged for ufo in ufos: self.assertEqual(ufo.info.familyName, 'MyFont')
def test_family_name_same_as_default(self): font = generate_minimal_font() instances_list = [{ 'name': 'Regular1' }, { 'name': 'Regular2', 'customParameters': [ { 'name': 'familyName', 'value': 'CustomFamily' }, ] }] font.instances = [ generate_instance_from_dict(i) for i in instances_list ] # 'MyFont' is the source family name, as returned from # 'generate_minimal_data' ufos, instance_data = to_ufos(font, include_instances=True, family_name='MyFont') instances = instance_data['data'] # only instances which don't have 'familyName' custom parameter # are included in returned list self.assertEqual(len(instances), 1) self.assertEqual(instances[0].name, 'Regular1') self.assertEqual(len(instances[0].customParameters), 0) # the masters' family name is unchanged for ufo in ufos: self.assertEqual(ufo.info.familyName, 'MyFont')
def test_master_with_light_weight_but_thin_name(self): font = generate_minimal_font() master = font.masters[0] name = 'Thin' # In Glyphs.app, show "Thin" in the sidebar weight = 'Light' # In Glyphs.app, have the light "n" icon width = None # No data => should be equivalent to Regular custom_name = 'Thin' master.set_all_name_components(name, weight, width, custom_name) assert master.name == 'Thin' assert master.weight == 'Light' ufo, = to_ufos(font) font_rt = to_glyphs([ufo]) master_rt = font_rt.masters[0] assert master_rt.name == 'Thin' assert master_rt.weight == 'Light' tmpdir = tempfile.mkdtemp() try: filename = os.path.join(tmpdir, 'test.glyphs') font_rt.save(filename) font_rt_written = GSFont(filename) master_rt_written = font_rt_written.masters[0] assert master_rt_written.name == 'Thin' assert master_rt_written.weight == 'Light' finally: shutil.rmtree(tmpdir)
def test_glyph_lib_componentsAlignment_and_componentsLocked(self): font = generate_minimal_font() add_glyph(font, "a") add_glyph(font, "b") composite_glyph = add_glyph(font, "c") add_component(font, "c", "a", (1, 0, 0, 1, 0, 0)) add_component(font, "c", "b", (1, 0, 0, 1, 0, 100)) comp1 = composite_glyph.layers[0].components[0] comp2 = composite_glyph.layers[0].components[1] self.assertEqual(comp1.alignment, 0) self.assertEqual(comp1.locked, False) ufo = to_ufos(font)[0] # all components have deault values, no lib key is written self.assertNotIn(GLYPHS_PREFIX + "componentsAlignment", ufo["c"].lib) self.assertNotIn(GLYPHS_PREFIX + "componentsLocked", ufo["c"].lib) comp2.alignment = -1 comp1.locked = True ufo = to_ufos(font)[0] # if any component has a non-default alignment/locked values, write # list of values for all of them self.assertIn(GLYPHS_PREFIX + "componentsAlignment", ufo["c"].lib) self.assertEqual(ufo["c"].lib[GLYPHS_PREFIX + "componentsAlignment"], [0, -1]) self.assertIn(GLYPHS_PREFIX + "componentsLocked", ufo["c"].lib) self.assertEqual(ufo["c"].lib[GLYPHS_PREFIX + "componentsLocked"], [True, False])
def test_glyph_color(self): font = generate_minimal_font() glyph = GSGlyph(name='a') glyph2 = GSGlyph(name='b') glyph3 = GSGlyph(name='c') glyph4 = GSGlyph(name='d') glyph.color = [244, 0, 138, 1] glyph2.color = 3 glyph3.color = 88 glyph4.color = [800, 0, 138, 1] font.glyphs.append(glyph) font.glyphs.append(glyph2) font.glyphs.append(glyph3) font.glyphs.append(glyph4) layer = GSLayer() layer2 = GSLayer() layer3 = GSLayer() layer4 = GSLayer() layer.layerId = font.masters[0].id layer2.layerId = font.masters[0].id layer3.layerId = font.masters[0].id layer4.layerId = font.masters[0].id glyph.layers.append(layer) glyph2.layers.append(layer2) glyph3.layers.append(layer3) glyph4.layers.append(layer4) ufo = to_ufos(font)[0] self.assertEqual(ufo['a'].lib.get('public.markColor'), '0.9569,0,0.5412,0.0039') self.assertEqual(ufo['b'].lib.get('public.markColor'), '0.97,1,0,1') self.assertEqual(ufo['c'].lib.get('public.markColor'), None) self.assertEqual(ufo['d'].lib.get('public.markColor'), None)
def test_GDEF(self): font = generate_minimal_font() for glyph in ('space', 'A', 'A.alt', 'wigglylinebelowcomb', 'wigglylinebelowcomb.alt', 'fi', 'fi.alt', 't_e_s_t', 't_e_s_t.alt'): add_glyph(font, glyph) add_anchor(font, 'A', 'bottom', 300, -10) add_anchor(font, 'wigglylinebelowcomb', '_bottom', 100, 40) add_anchor(font, 'fi', 'caret_1', 150, 0) add_anchor(font, 't_e_s_t.alt', 'caret_1', 200, 0) add_anchor(font, 't_e_s_t.alt', 'caret_2', 400, 0) add_anchor(font, 't_e_s_t.alt', 'caret_3', 600, 0) ufo = to_ufos(font)[0] self.assertEqual(ufo.features.text.splitlines(), [ 'table GDEF {', ' # automatic', ' GlyphClassDef', ' [A], # Base', ' [fi t_e_s_t.alt], # Liga', ' [wigglylinebelowcomb wigglylinebelowcomb.alt], # Mark', ' ;', ' LigatureCaretByPos fi 150;', ' LigatureCaretByPos t_e_s_t.alt 200 400 600;', '} GDEF;', ])
def test_subCategory(self): font = generate_minimal_font() add_glyph(font, 'foo')['subCategory'] = 'Nonspacing' add_glyph(font, 'bar') ufo = to_ufos(font)[0] subCategory_key = GLYPHLIB_PREFIX + 'subCategory' self.assertEqual(ufo['foo'].lib.get(subCategory_key), 'Nonspacing') self.assertFalse(subCategory_key in ufo['bar'].lib)
def test_category(self): font = generate_minimal_font() add_glyph(font, 'foo')['category'] = 'Mark' add_glyph(font, 'bar') ufo = to_ufos(font)[0] category_key = GLYPHLIB_PREFIX + 'category' self.assertEqual(ufo['foo'].lib.get(category_key), 'Mark') self.assertFalse(category_key in ufo['bar'].lib)
def test_set_glyphOrder_no_custom_param(self): font = generate_minimal_font() add_glyph(font, 'C') add_glyph(font, 'B') add_glyph(font, 'A') add_glyph(font, 'Z') glyphOrder = to_ufos(font)[0].lib[PUBLIC_PREFIX + 'glyphOrder'] self.assertEqual(glyphOrder, ['C', 'B', 'A', 'Z'])
def test_GDEF_fractional_caret_position(self): # Some Glyphs sources happen to contain fractional caret positions. # In the Adobe feature file syntax (and binary OpenType GDEF tables), # caret positions must be integers. font = generate_minimal_font() add_glyph(font, 'fi') add_anchor(font, 'fi', 'caret_1', 499.9876, 0) self.assertIn('LigatureCaretByPos fi 500;', to_ufos(font)[0].features.text)
def test_warn_no_version(self): """Test that a warning is printed when app version is missing.""" font = generate_minimal_font() font.appVersion = "0" with CapturingLogHandler(builder.logger, "WARNING") as captor: to_ufos(font) self.assertEqual( len([r for r in captor.records if "outdated version" in r.msg]), 1)
def test_set_glyphOrder_with_custom_param(self): font = generate_minimal_font() font.customParameters['glyphOrder'] = ['A', 'B', 'C'] add_glyph(font, 'C') add_glyph(font, 'B') add_glyph(font, 'A') # glyphs outside glyphOrder are appended at the end add_glyph(font, 'Z') glyphOrder = to_ufos(font)[0].lib[PUBLIC_PREFIX + 'glyphOrder'] self.assertEqual(glyphOrder, ['A', 'B', 'C', 'Z'])
def test_GDEF_custom_category_subCategory(self): font = generate_minimal_font() add_glyph(font, 'foo')['subCategory'] = 'Ligature' add_anchor(font, 'foo', 'top', 400, 1000) bar = add_glyph(font, 'bar') bar['category'], bar['subCategory'] = 'Mark', 'Nonspacing' baz = add_glyph(font, 'baz') baz['category'], baz['subCategory'] = 'Mark', 'Spacing Combining' features = to_ufos(font)[0].features.text self.assertIn('[foo], # Liga', features) self.assertIn('[bar baz], # Mark', features)
def test_postscript_name_from_glyph_name(self): font = generate_minimal_font() # in GlyphData (and AGLFN) without a 'production' name add_glyph(font, 'A') # not in GlyphData, no production name add_glyph(font, 'foobar') # in GlyphData with a 'production' name add_glyph(font, 'C-fraktur') ufo = to_ufos(font)[0] postscriptNames = ufo.lib.get('public.postscriptNames') self.assertEqual(postscriptNames, {'C-fraktur': 'uni212D'})
def test_glyph_lib_metricsKeys(self): font = generate_minimal_font() glyph = add_glyph(font, "x") glyph.leftMetricsKey = "y" glyph.rightMetricsKey = "z" assert glyph.widthMetricsKey is None ufo = to_ufos(font)[0] self.assertEqual(ufo["x"].lib[GLYPHLIB_PREFIX + "leftMetricsKey"], "y") self.assertEqual(ufo["x"].lib[GLYPHLIB_PREFIX + "rightMetricsKey"], "z") self.assertNotIn(GLYPHLIB_PREFIX + "widthMetricsKey", ufo["x"].lib)
def test_set_blue_values(self): """Test that blue values are set correctly from alignment zones.""" data_in = [GSAlignmentZone(pos=500, size=15), GSAlignmentZone(pos=400, size=-15), GSAlignmentZone(pos=0, size=-15), GSAlignmentZone(pos=-200, size=15), GSAlignmentZone(pos=-300, size=-15)] expected_blue_values = [-200, -185, -15, 0, 500, 515] expected_other_blues = [-315, -300, 385, 400] font = generate_minimal_font() font.masters[0].alignmentZones = data_in ufo = to_ufos(font)[0] self.assertEqual(ufo.info.postscriptBlueValues, expected_blue_values) self.assertEqual(ufo.info.postscriptOtherBlues, expected_other_blues)
def test_variation_font_origin(self): font = generate_minimal_font() name = 'Variation Font Origin' value = 'Light' font.customParameters[name] = value ufos, instances = to_ufos(font, include_instances=True) for ufo in ufos: key = GLYPHS_PREFIX + name self.assertIn(key, ufo.lib) self.assertEqual(ufo.lib[key], value) self.assertIn(name, instances) self.assertEqual(instances[name], value)
def test_glyph_lib_Export(self): font = generate_minimal_font() glyph = add_glyph(font, "a") self.assertEqual(glyph.export, True) ufo = to_ufos(font)[0] self.assertNotIn(GLYPHLIB_PREFIX + "Export", ufo["a"].lib) glyph.export = False ufo = to_ufos(font)[0] self.assertEqual(ufo["a"].lib[GLYPHLIB_PREFIX + "Export"], False)
def test_propagate_anchors(self): """Test anchor propagation for some relatively complicated cases.""" font = generate_minimal_font() glyphs = ( ('sad', [], [('bottom', 50, -50), ('top', 50, 150)]), ('dotabove', [], [('top', 0, 150), ('_top', 0, 100)]), ('dotbelow', [], [('bottom', 0, -50), ('_bottom', 0, 0)]), ('dad', [('sad', 0, 0), ('dotabove', 50, 50)], []), ('dadDotbelow', [('dad', 0, 0), ('dotbelow', 50, -50)], []), ('yod', [], [('bottom', 50, -50)]), ('yodyod', [('yod', 0, 0), ('yod', 100, 0)], []), ) for name, component_data, anchor_data in glyphs: glyph = add_glyph(font, name) for n, x, y, in anchor_data: add_anchor(font, name, n, x, y) for n, x, y in component_data: add_component(font, name, n, (1, 0, 0, 1, x, y)) ufos = to_ufos(font) ufo = ufos[0] glyph = ufo['dadDotbelow'] self.assertEqual(len(glyph.anchors), 2) # check propagated anchors are appended in a deterministic order self.assertEqual( [anchor.name for anchor in glyph.anchors], ['bottom', 'top'] ) for anchor in glyph.anchors: self.assertEqual(anchor.x, 50) if anchor.name == 'bottom': self.assertEqual(anchor.y, -100) else: self.assertEqual(anchor.name, 'top') self.assertEqual(anchor.y, 200) glyph = ufo['yodyod'] self.assertEqual(len(glyph.anchors), 2) for anchor in glyph.anchors: self.assertEqual(anchor.y, -50) if anchor.name == 'bottom_1': self.assertEqual(anchor.x, 50) else: self.assertEqual(anchor.name, 'bottom_2') self.assertEqual(anchor.x, 150)
def test_supplementary_layers(self): """Test sub layers.""" font = generate_minimal_font() glyph = GSGlyph(name="a") font.glyphs.append(glyph) layer = GSLayer() layer.layerId = font.masters[0].id layer.width = 0 glyph.layers.append(layer) sublayer = GSLayer() sublayer.associatedMasterId = font.masters[0].id sublayer.width = 0 sublayer.name = "SubLayer" glyph.layers.append(sublayer) ufo = to_ufos(font)[0] self.assertEqual([l.name for l in ufo.layers], ["public.default", "SubLayer"])
def test_minimal_data(self): """Test the minimal data that must be provided to generate UFOs, and in some cases that additional redundant data is not set. """ font = generate_minimal_font() family_name = font.familyName ufos = to_ufos(font) self.assertEqual(len(ufos), 1) ufo = ufos[0] self.assertEqual(len(ufo), 0) self.assertEqual(ufo.info.familyName, family_name) # self.assertEqual(ufo.info.styleName, 'Regular') self.assertEqual(ufo.info.versionMajor, 1) self.assertEqual(ufo.info.versionMinor, 0) self.assertIsNone(ufo.info.openTypeNameVersion)
def test_fail_during_anchor_propagation(self): """Fix https://github.com/googlei18n/glyphsLib/issues/317""" font = generate_minimal_font() glyphs = ( # This glyph has components that don't exist in the font ('yodyod', [('yod', 0, 0), ('yod', 100, 0)], []), ) for name, component_data, anchor_data in glyphs: add_glyph(font, name) for n, x, y, in anchor_data: add_anchor(font, name, n, x, y) for n, x, y in component_data: add_component(font, name, n, (1, 0, 0, 1, x, y)) # We just want the call to `to_ufos` to not crash assert to_ufos(font)
def _run_guideline_test(self, data_in, expected): font = generate_minimal_font() glyph = GSGlyph(name='a') font.glyphs.append(glyph) layer = GSLayer() layer.layerId = font.masters[0].id layer.width = 0 for guide_data in data_in: pt = point(value=guide_data['position'][0], value2=guide_data['position'][1]) guide = GSGuideLine() guide.position = pt guide.angle = guide_data['angle'] layer.guides.append(guide) glyph.layers.append(layer) ufo = to_ufos(font)[0] self.assertEqual(ufo['a'].guidelines, expected)
def test_load_kerning(self): """Test that kerning conflicts are resolved correctly. Correct resolution is defined as such: the last time a pair is found in a kerning rule, that rule is used for the pair. """ font = generate_minimal_font() # generate classes 'A': ['A', 'a'] and 'V': ['V', 'v'] for glyph_name in ('A', 'a', 'V', 'v'): glyph = add_glyph(font, glyph_name) glyph.rightKerningGroup = glyph_name.upper() glyph.leftKerningGroup = glyph_name.upper() # classes are referenced in Glyphs kerning using old MMK names font.kerning = { font.masters[0].id: collections.OrderedDict(( ('@MMK_L_A', collections.OrderedDict(( ('@MMK_R_V', -250), ('v', -100), ))), ('a', collections.OrderedDict((('@MMK_R_V', 100), ))), )) } ufos = to_ufos(font) ufo = ufos[0] # these rules should be obvious self.assertEqual(ufo.kerning['public.kern1.A', 'public.kern2.V'], -250) self.assertEqual(ufo.kerning['a', 'public.kern2.V'], 100) # this rule results from breaking up (kern1.A, v, -100) # due to conflict with (a, kern2.V, 100) self.assertEqual(ufo.kerning['A', 'v'], -100)
def test_mark_nonspacing_zero_width(self): font = generate_minimal_font() add_glyph(font, 'dieresiscomb').layers[0].width = 100 foo = add_glyph(font, 'foo') foo.category = 'Mark' foo.subCategory = 'Nonspacing' foo.layers[0].width = 200 bar = add_glyph(font, 'bar') bar.category = 'Mark' bar.subCategory = 'Nonspacing' bar.layers[0].width = 0 ufo = to_ufos(font)[0] originalWidth_key = GLYPHLIB_PREFIX + 'originalWidth' self.assertEqual(ufo['dieresiscomb'].width, 0) self.assertEqual(ufo['dieresiscomb'].lib.get(originalWidth_key), 100) self.assertEqual(ufo['foo'].width, 0) self.assertEqual(ufo['foo'].lib.get(originalWidth_key), 200) self.assertEqual(ufo['bar'].width, 0) self.assertFalse(originalWidth_key in ufo['bar'].lib)
def test_coerce_to_bool(self): font = generate_minimal_font() font.customParameters['Disable Last Change'] = 'Truthy' ufo = to_ufos(font)[0] self.assertEqual(True, ufo.lib[GLYPHS_PREFIX + 'disablesLastChange'])
def test_lib_custom(self): font = generate_minimal_font() font.masters[0].customName = 'FooBar' ufo = to_ufos(font)[0] self.assertEqual(ufo.lib[GLYPHS_PREFIX + 'customName'], 'FooBar')
def test_lib_no_custom(self): font = generate_minimal_font() ufo = to_ufos(font)[0] self.assertFalse(GLYPHS_PREFIX + 'customName' in ufo.lib)
def test_lib_width(self): font = generate_minimal_font() font.masters[0].width = 'Condensed' ufo = to_ufos(font)[0] self.assertEqual(ufo.lib[GLYPHS_PREFIX + 'width'], 'Condensed')