fonttools/Tests/mtiLib/mti_test.py
Just van Rossum 5fc65d7168
Misc py23 cleanups (#2243)
* Replaced all from ...py23 import * with explicit name imports, or removed completely when possible.
* Replaced tounicode() with tostr()
* Changed all BytesIO ans StringIO imports to from io import ..., replaced all UnicodeIO with StringIO.
* Replaced all unichr() with chr()
* Misc minor tweaks and fixes
2021-03-29 11:45:58 +02:00

235 lines
10 KiB
Python

from fontTools.misc.xmlWriter import XMLWriter
from fontTools.ttLib import TTFont
from fontTools import mtiLib
import difflib
from io import StringIO
import os
import sys
import unittest
class MtiTest(unittest.TestCase):
GLYPH_ORDER = ['.notdef',
'a', 'b', 'pakannada', 'phakannada', 'vakannada', 'pevowelkannada',
'phevowelkannada', 'vevowelkannada', 'uvowelsignkannada', 'uuvowelsignkannada',
'uvowelsignaltkannada', 'uuvowelsignaltkannada', 'uuvowelsignsinh',
'uvowelsignsinh', 'rakarsinh', 'zero', 'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'slash', 'fraction', 'A', 'B', 'C', 'fi',
'fl', 'breve', 'acute', 'uniFB01', 'ffi', 'grave', 'commaacent', 'dotbelow',
'dotabove', 'cedilla', 'commaaccent', 'Acircumflex', 'V', 'T', 'acircumflex',
'Aacute', 'Agrave', 'O', 'Oacute', 'Ograve', 'Ocircumflex', 'aacute', 'agrave',
'aimatrabindigurmukhi', 'aimatragurmukhi', 'aimatratippigurmukhi',
'aumatrabindigurmukhi', 'aumatragurmukhi', 'bindigurmukhi',
'eematrabindigurmukhi', 'eematragurmukhi', 'eematratippigurmukhi',
'oomatrabindigurmukhi', 'oomatragurmukhi', 'oomatratippigurmukhi',
'lagurmukhi', 'lanuktagurmukhi', 'nagurmukhi', 'nanuktagurmukhi',
'ngagurmukhi', 'nganuktagurmukhi', 'nnagurmukhi', 'nnanuktagurmukhi',
'tthagurmukhi', 'tthanuktagurmukhi', 'bsuperior', 'isuperior', 'vsuperior',
'wsuperior', 'periodsuperior', 'osuperior', 'tsuperior', 'dollarsuperior',
'fsuperior', 'gsuperior', 'zsuperior', 'dsuperior', 'psuperior', 'hsuperior',
'oesuperior', 'aesuperior', 'centsuperior', 'esuperior', 'lsuperior',
'qsuperior', 'csuperior', 'asuperior', 'commasuperior', 'xsuperior',
'egravesuperior', 'usuperior', 'rsuperior', 'nsuperior', 'ssuperior',
'msuperior', 'jsuperior', 'ysuperior', 'ksuperior', 'guilsinglright',
'guilsinglleft', 'uniF737', 'uniE11C', 'uniE11D', 'uniE11A', 'uni2077',
'uni2087', 'uniE11B', 'uniE119', 'uniE0DD', 'uniE0DE', 'uniF736', 'uniE121',
'uniE122', 'uniE11F', 'uni2076', 'uni2086', 'uniE120', 'uniE11E', 'uniE0DB',
'uniE0DC', 'uniF733', 'uniE12B', 'uniE12C', 'uniE129', 'uni00B3', 'uni2083',
'uniE12A', 'uniE128', 'uniF732', 'uniE133', 'uniE134', 'uniE131', 'uni00B2',
'uni2082', 'uniE132', 'uniE130', 'uniE0F9', 'uniF734', 'uniE0D4', 'uniE0D5',
'uniE0D2', 'uni2074', 'uni2084', 'uniE0D3', 'uniE0D1', 'uniF730', 'uniE13D',
'uniE13E', 'uniE13A', 'uni2070', 'uni2080', 'uniE13B', 'uniE139', 'uniE13C',
'uniF739', 'uniE0EC', 'uniE0ED', 'uniE0EA', 'uni2079', 'uni2089', 'uniE0EB',
'uniE0E9', 'uniF735', 'uniE0CD', 'uniE0CE', 'uniE0CB', 'uni2075', 'uni2085',
'uniE0CC', 'uniE0CA', 'uniF731', 'uniE0F3', 'uniE0F4', 'uniE0F1', 'uni00B9',
'uni2081', 'uniE0F2', 'uniE0F0', 'uniE0F8', 'uniF738', 'uniE0C0', 'uniE0C1',
'uniE0BE', 'uni2078', 'uni2088', 'uniE0BF', 'uniE0BD', 'I', 'Ismall', 't', 'i',
'f', 'IJ', 'J', 'IJsmall', 'Jsmall', 'tt', 'ij', 'j', 'ffb', 'ffh', 'h', 'ffk',
'k', 'ffl', 'l', 'fft', 'fb', 'ff', 'fh', 'fj', 'fk', 'ft', 'janyevoweltelugu',
'kassevoweltelugu', 'jaivoweltelugu', 'nyasubscripttelugu', 'kaivoweltelugu',
'ssasubscripttelugu', 'bayi1', 'jeemi1', 'kafi1', 'ghafi1', 'laami1', 'kafm1',
'ghafm1', 'laamm1', 'rayf2', 'reyf2', 'yayf2', 'zayf2', 'fayi1', 'ayehf2',
'hamzayeharabf2', 'hamzayehf2', 'yehf2', 'ray', 'rey', 'zay', 'yay', 'dal',
'del', 'zal', 'rayf1', 'reyf1', 'yayf1', 'zayf1', 'ayehf1', 'hamzayeharabf1',
'hamzayehf1', 'yehf1', 'dal1', 'del1', 'zal1', 'onehalf', 'onehalf.alt',
'onequarter', 'onequarter.alt', 'threequarters', 'threequarters.alt',
'AlefSuperiorNS', 'DammaNS', 'DammaRflxNS', 'DammatanNS', 'Fatha2dotsNS',
'FathaNS', 'FathatanNS', 'FourDotsAboveNS', 'HamzaAboveNS', 'MaddaNS',
'OneDotAbove2NS', 'OneDotAboveNS', 'ShaddaAlefNS', 'ShaddaDammaNS',
'ShaddaDammatanNS', 'ShaddaFathatanNS', 'ShaddaKasraNS', 'ShaddaKasratanNS',
'ShaddaNS', 'SharetKafNS', 'SukunNS', 'ThreeDotsDownAboveNS',
'ThreeDotsUpAboveNS', 'TwoDotsAboveNS', 'TwoDotsVerticalAboveNS', 'UltapeshNS',
'WaslaNS', 'AinIni.12m_MeemFin.02', 'AinIni_YehBarreeFin',
'AinMed_YehBarreeFin', 'BehxIni_MeemFin', 'BehxIni_NoonGhunnaFin',
'BehxIni_RehFin', 'BehxIni_RehFin.b', 'BehxMed_MeemFin.py',
'BehxMed_NoonGhunnaFin', 'BehxMed_NoonGhunnaFin.cup', 'BehxMed_RehFin',
'BehxMed_RehFin.cup', 'BehxMed_YehxFin', 'FehxMed_YehBarreeFin',
'HahIni_YehBarreeFin', 'KafIni_YehBarreeFin', 'KafMed.12_YehxFin.01',
'KafMed_MeemFin', 'KafMed_YehBarreeFin', 'LamAlefFin', 'LamAlefFin.cup',
'LamAlefFin.cut', 'LamAlefFin.short', 'LamAlefSep', 'LamIni_MeemFin',
'LamIni_YehBarreeFin', 'LamMed_MeemFin', 'LamMed_MeemFin.b', 'LamMed_YehxFin',
'LamMed_YehxFin.cup', 'TahIni_YehBarreeFin', 'null', 'CR', 'space',
'exclam', 'quotedbl', 'numbersign',
]
# Feature files in data/*.txt; output gets compared to data/*.ttx.
TESTS = {
None: (
'mti/cmap',
),
'cmap': (
'mti/cmap',
),
'GSUB': (
'featurename-backward',
'featurename-forward',
'lookupnames-backward',
'lookupnames-forward',
'mixed-toplevels',
'mti/scripttable',
'mti/chainedclass',
'mti/chainedcoverage',
'mti/chained-glyph',
'mti/gsubalternate',
'mti/gsubligature',
'mti/gsubmultiple',
'mti/gsubreversechanined',
'mti/gsubsingle',
),
'GPOS': (
'mti/scripttable',
'mti/chained-glyph',
'mti/gposcursive',
'mti/gposkernset',
'mti/gposmarktobase',
'mti/gpospairclass',
'mti/gpospairglyph',
'mti/gpossingle',
'mti/mark-to-ligature',
),
'GDEF': (
'mti/gdefattach',
'mti/gdefclasses',
'mti/gdefligcaret',
'mti/gdefmarkattach',
'mti/gdefmarkfilter',
),
}
# TODO:
# https://github.com/Monotype/OpenType_Table_Source/issues/12
#
# 'mti/featuretable'
# 'mti/contextclass'
# 'mti/contextcoverage'
# 'mti/context-glyph'
def __init__(self, methodName):
unittest.TestCase.__init__(self, methodName)
# Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
# and fires deprecation warnings if a program uses the old name.
if not hasattr(self, "assertRaisesRegex"):
self.assertRaisesRegex = self.assertRaisesRegexp
def setUp(self):
pass
def tearDown(self):
pass
@staticmethod
def getpath(testfile):
path, _ = os.path.split(__file__)
return os.path.join(path, "data", testfile)
def expect_ttx(self, expected_ttx, actual_ttx, fromfile=None, tofile=None):
expected = [l+'\n' for l in expected_ttx.split('\n')]
actual = [l+'\n' for l in actual_ttx.split('\n')]
if actual != expected:
sys.stderr.write('\n')
for line in difflib.unified_diff(
expected, actual, fromfile=fromfile, tofile=tofile):
sys.stderr.write(line)
self.fail("TTX output is different from expected")
@classmethod
def create_font(celf):
font = TTFont()
font.setGlyphOrder(celf.GLYPH_ORDER)
return font
def check_mti_file(self, name, tableTag=None):
xml_expected_path = self.getpath("%s.ttx" % name + ('.'+tableTag if tableTag is not None else ''))
with open(xml_expected_path, 'rt', encoding="utf-8") as xml_expected_file:
xml_expected = xml_expected_file.read()
font = self.create_font()
with open(self.getpath("%s.txt" % name), 'rt', encoding="utf-8") as f:
table = mtiLib.build(f, font, tableTag=tableTag)
if tableTag is not None:
self.assertEqual(tableTag, table.tableTag)
tableTag = table.tableTag
# Make sure it compiles.
blob = table.compile(font)
# Make sure it decompiles.
decompiled = table.__class__()
decompiled.decompile(blob, font)
# XML from built object.
writer = XMLWriter(StringIO(), newlinestr='\n')
writer.begintag(tableTag); writer.newline()
table.toXML(writer, font)
writer.endtag(tableTag); writer.newline()
xml_built = writer.file.getvalue()
# XML from decompiled object.
writer = XMLWriter(StringIO(), newlinestr='\n')
writer.begintag(tableTag); writer.newline()
decompiled.toXML(writer, font)
writer.endtag(tableTag); writer.newline()
xml_binary = writer.file.getvalue()
self.expect_ttx(xml_binary, xml_built, fromfile='decompiled', tofile='built')
self.expect_ttx(xml_expected, xml_built, fromfile=xml_expected_path, tofile='built')
from fontTools.misc import xmlReader
f = StringIO()
f.write(xml_expected)
f.seek(0)
font2 = TTFont()
font2.setGlyphOrder(font.getGlyphOrder())
reader = xmlReader.XMLReader(f, font2)
reader.read(rootless=True)
# XML from object read from XML.
writer = XMLWriter(StringIO(), newlinestr='\n')
writer.begintag(tableTag); writer.newline()
font2[tableTag].toXML(writer, font)
writer.endtag(tableTag); writer.newline()
xml_fromxml = writer.file.getvalue()
self.expect_ttx(xml_expected, xml_fromxml, fromfile=xml_expected_path, tofile='fromxml')
def generate_mti_file_test(name, tableTag=None):
return lambda self: self.check_mti_file(os.path.join(*name.split('/')), tableTag=tableTag)
for tableTag,tests in MtiTest.TESTS.items():
for name in tests:
setattr(MtiTest, "test_MtiFile_%s%s" % (name, '_'+tableTag if tableTag else ''),
generate_mti_file_test(name, tableTag=tableTag))
if __name__ == "__main__":
if len(sys.argv) > 1:
from fontTools.mtiLib import main
font = MtiTest.create_font()
sys.exit(main(sys.argv[1:], font))
sys.exit(unittest.main())