fonttools/Tests/mtiLib/mti_test.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

518 lines
12 KiB
Python
Raw Normal View History

from fontTools.misc.xmlWriter import XMLWriter
from fontTools.ttLib import TTFont
from fontTools.feaLib.lookupDebugInfo import LOOKUP_DEBUG_ENV_VAR
from fontTools import mtiLib
import difflib
from io import StringIO
import os
import sys
import pytest
@pytest.fixture(autouse=True)
def set_lookup_debug_env_var(monkeypatch):
monkeypatch.setenv(LOOKUP_DEBUG_ENV_VAR, "1")
class MtiTest:
GLYPH_ORDER = [
".notdef",
2016-12-27 13:42:17 -05:00
"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",
2022-12-13 11:26:36 +00:00
"fb",
"ff",
"fh",
2016-12-27 13:42:17 -05:00
"fj",
2022-12-13 11:26:36 +00:00
"fk",
2016-12-27 13:42:17 -05:00
"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 = {
2016-12-26 16:39:50 -05:00
None: ("mti/cmap",),
"cmap": ("mti/cmap",),
2022-12-13 11:26:36 +00:00
"GSUB": (
2016-12-26 17:35:21 -05:00
"featurename-backward",
"featurename-forward",
"lookupnames-backward",
"lookupnames-forward",
"mixed-toplevels",
2016-12-26 16:39:50 -05:00
"mti/scripttable",
"mti/chainedclass",
"mti/chainedcoverage",
"mti/chained-glyph",
2016-12-26 16:39:50 -05:00
"mti/gsubalternate",
"mti/gsubligature",
"mti/gsubmultiple",
"mti/gsubreversechanined",
"mti/gsubsingle",
),
"GPOS": (
"mti/scripttable",
"mti/chained-glyph",
2016-12-26 16:39:50 -05:00
"mti/gposcursive",
2016-12-26 17:14:39 -05:00
"mti/gposkernset",
"mti/gposmarktobase",
2016-12-26 17:14:39 -05:00
"mti/gpospairclass",
2016-12-26 16:39:50 -05:00
"mti/gpospairglyph",
"mti/gpossingle",
"mti/mark-to-ligature",
),
"GDEF": (
"mti/gdefattach",
2016-12-26 17:14:39 -05:00
"mti/gdefclasses",
2016-12-26 16:39:50 -05:00
"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):
2016-12-26 16:39:50 -05:00
expected = [l + "\n" for l in expected_ttx.split("\n")]
actual = [l + "\n" for l in actual_ttx.split("\n")]
if actual != expected:
2016-12-26 20:29:06 -05:00
sys.stderr.write("\n")
for line in difflib.unified_diff(
expected, actual, fromfile=fromfile, tofile=tofile
):
2016-12-26 20:29:06 -05:00
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 "")
2022-12-13 11:26:36 +00:00
)
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)
2016-12-26 16:39:50 -05:00
if tableTag is not None:
assert tableTag == table.tableTag
2016-12-26 16:39:50 -05:00
tableTag = table.tableTag
2016-12-26 16:39:50 -05:00
# Make sure it compiles.
blob = table.compile(font)
2016-12-26 16:39:50 -05:00
# Make sure it decompiles.
decompiled = table.__class__()
decompiled.decompile(blob, font)
2016-12-26 16:39:50 -05:00
# XML from built object.
writer = XMLWriter(StringIO())
2016-12-26 16:39:50 -05:00
writer.begintag(tableTag)
writer.newline()
table.toXML(writer, font)
writer.endtag(tableTag)
writer.newline()
xml_built = writer.file.getvalue()
2016-12-26 16:39:50 -05:00
# XML from decompiled object.
writer = XMLWriter(StringIO())
2016-12-26 16:39:50 -05:00
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
2022-12-13 11:26:36 +00:00
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"
)
2022-12-13 11:26:36 +00:00
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
2022-12-13 11:26:36 +00:00
font = MtiTest.create_font()
sys.exit(main(sys.argv[1:], font))
sys.exit(pytest.main(sys.argv))