fonttools/Tests/mtiLib/mti_test.py
2023-03-07 12:00:50 +00:00

514 lines
12 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 pytest
class MtiTest:
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'
@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)
pytest.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:
assert 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())
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())
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())
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(pytest.main(sys.argv))