514 lines
12 KiB
Python
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))
|