[otTables] Use XML snippets for testing fromXML() methods
This should make the unit tests more readable, and it also prevents failures where a changed fromXML() implementation fails to ignore interspersed whitespace. This has recently caused some developer nuisance; see https://github.com/behdad/fonttools/pull/367. Instead of having a custom parser implementation, it would be nicer to call the actual XMLReader. However, XMLReader has a deeply built-in assumption that it is processing an entire TTX file. Changing this assumption would certainly be possible, but it would need a re-write of the XMLReader code; having a custom parser just for unit tests seems less involved.
This commit is contained in:
parent
99acc50215
commit
d63885e337
42
Lib/fontTools/misc/testTools.py
Normal file
42
Lib/fontTools/misc/testTools.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""Helpers for writing unit tests."""
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
|
||||
|
||||
def parseXML(xmlSnippet):
|
||||
"""Parses a snippet of XML.
|
||||
|
||||
The result is in the same format that would be returned by
|
||||
XMLReader, but the parser imposes no constraints on the root
|
||||
element so it can be called on small snippets of TTX files.
|
||||
"""
|
||||
# To support snippets with multiple elements, we add a fake root.
|
||||
reader = TestXMLReader_()
|
||||
reader.parser.Parse("<root>%s</root>" % xmlSnippet, 0)
|
||||
return reader.root[2]
|
||||
|
||||
|
||||
class TestXMLReader_(object):
|
||||
def __init__(self):
|
||||
from xml.parsers.expat import ParserCreate
|
||||
self.parser = ParserCreate()
|
||||
self.parser.StartElementHandler = self.startElement_
|
||||
self.parser.EndElementHandler = self.endElement_
|
||||
self.parser.CharacterDataHandler = self.addCharacterData_
|
||||
self.root = None
|
||||
self.stack = []
|
||||
|
||||
def startElement_(self, name, attrs):
|
||||
element = (name, attrs, [])
|
||||
if self.stack:
|
||||
self.stack[-1][2].append(element)
|
||||
else:
|
||||
self.root = element
|
||||
self.stack.append(element)
|
||||
|
||||
def endElement_(self, name):
|
||||
self.stack.pop()
|
||||
|
||||
def addCharacterData_(self, data):
|
||||
self.stack[-1][2].append(data)
|
30
Lib/fontTools/misc/testTools_test.py
Normal file
30
Lib/fontTools/misc/testTools_test.py
Normal file
@ -0,0 +1,30 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from __future__ import unicode_literals
|
||||
from fontTools.misc.py23 import *
|
||||
import fontTools.misc.testTools as testTools
|
||||
import os
|
||||
import unittest
|
||||
|
||||
|
||||
class TestToolsTest(unittest.TestCase):
|
||||
def test_parseXML(self):
|
||||
self.assertEqual(testTools.parseXML(
|
||||
'<Foo n="1"/>'
|
||||
'<Foo n="2">'
|
||||
' some text'
|
||||
' <Bar color="red"/>'
|
||||
' some more text'
|
||||
'</Foo>'
|
||||
'<Foo n="3"/>'), [
|
||||
("Foo", {"n": "1"}, []),
|
||||
("Foo", {"n": "2"}, [
|
||||
" some text ",
|
||||
("Bar", {"color": "red"}, []),
|
||||
" some more text",
|
||||
]),
|
||||
("Foo", {"n": "3"}, [])
|
||||
])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
@ -1,5 +1,6 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc.testTools import parseXML
|
||||
from fontTools.misc.xmlWriter import XMLWriter
|
||||
import fontTools.ttLib.tables.otTables as otTables
|
||||
import unittest
|
||||
@ -83,9 +84,11 @@ class SingleSubstTest(unittest.TestCase):
|
||||
|
||||
def test_fromXML(self):
|
||||
table = otTables.SingleSubst()
|
||||
table.fromXML("Substitution", {"in": "A", "out": "a"}, [], self.font)
|
||||
table.fromXML("Substitution", {"in": "B", "out": "b"}, [], self.font)
|
||||
table.fromXML("Substitution", {"in": "C", "out": "c"}, [], self.font)
|
||||
for name, attrs, content in parseXML(
|
||||
'<Substitution in="A" out="a"/>'
|
||||
'<Substitution in="B" out="b"/>'
|
||||
'<Substitution in="C" out="c"/>'):
|
||||
table.fromXML(name, attrs, content, self.font)
|
||||
self.assertEqual(table.mapping, {"A": "a", "B": "b", "C": "c"})
|
||||
|
||||
|
||||
@ -135,28 +138,30 @@ class MultipleSubstTest(unittest.TestCase):
|
||||
|
||||
def test_fromXML(self):
|
||||
table = otTables.MultipleSubst()
|
||||
table.fromXML("Substitution",
|
||||
{"in": "c_t", "out": "c,t"}, [], self.font)
|
||||
table.fromXML("Substitution",
|
||||
{"in": "f_f_i", "out": "f,f,i"}, [], self.font)
|
||||
for name, attrs, content in parseXML(
|
||||
'<Substitution in="c_t" out="c,t"/>'
|
||||
'<Substitution in="f_f_i" out="f,f,i"/>'):
|
||||
table.fromXML(name, attrs, content, self.font)
|
||||
self.assertEqual(table.mapping,
|
||||
{'c_t': ['c', 't'], 'f_f_i': ['f', 'f', 'i']})
|
||||
|
||||
def test_fromXML_oldFormat(self):
|
||||
table = otTables.MultipleSubst()
|
||||
table.fromXML("Coverage", {}, [
|
||||
("Glyph", {"value": "c_t"}, []),
|
||||
("Glyph", {"value": "f_f_i"}, [])
|
||||
], self.font)
|
||||
table.fromXML("Sequence", {"index": "0"}, [
|
||||
("Substitute", {"index": "0", "value": "c"}, []),
|
||||
("Substitute", {"index": "1", "value": "t"}, [])
|
||||
], self.font)
|
||||
table.fromXML("Sequence", {"index": "1"}, [
|
||||
("Substitute", {"index": "0", "value": "f"}, []),
|
||||
("Substitute", {"index": "1", "value": "f"}, []),
|
||||
("Substitute", {"index": "2", "value": "i"}, [])
|
||||
], self.font)
|
||||
for name, attrs, content in parseXML(
|
||||
'<Coverage>'
|
||||
' <Glyph value="c_t"/>'
|
||||
' <Glyph value="f_f_i"/>'
|
||||
'</Coverage>'
|
||||
'<Sequence index="0">'
|
||||
' <Substitute index="0" value="c"/>'
|
||||
' <Substitute index="1" value="t"/>'
|
||||
'</Sequence>'
|
||||
'<Sequence index="1">'
|
||||
' <Substitute index="0" value="f"/>'
|
||||
' <Substitute index="1" value="f"/>'
|
||||
' <Substitute index="2" value="i"/>'
|
||||
'</Sequence>'):
|
||||
table.fromXML(name, attrs, content, self.font)
|
||||
self.assertEqual(table.mapping,
|
||||
{'c_t': ['c', 't'], 'f_f_i': ['f', 'f', 'i']})
|
||||
|
||||
@ -255,10 +260,12 @@ class LigatureSubstTest(unittest.TestCase):
|
||||
|
||||
def test_fromXML(self):
|
||||
table = otTables.LigatureSubst()
|
||||
table.fromXML("LigatureSet", {"glyph": "f"}, [
|
||||
("Ligature", {"components": "f,f,i", "glyph": "f_f_i"}, []),
|
||||
("Ligature", {"components": "f,f", "glyph": "f_f"}, []),
|
||||
], self.font)
|
||||
for name, attrs, content in parseXML(
|
||||
'<LigatureSet glyph="f">'
|
||||
' <Ligature components="f,f,i" glyph="f_f_i"/>'
|
||||
' <Ligature components="f,f" glyph="f_f"/>'
|
||||
'</LigatureSet>'):
|
||||
table.fromXML(name, attrs, content, self.font)
|
||||
self.assertEqual(set(table.ligatures.keys()), {"f"})
|
||||
[ffi, ff] = table.ligatures["f"]
|
||||
self.assertEqual(ffi.LigGlyph, "f_f_i")
|
||||
@ -327,13 +334,15 @@ class AlternateSubstTest(unittest.TestCase):
|
||||
|
||||
def test_fromXML(self):
|
||||
table = otTables.AlternateSubst()
|
||||
table.fromXML("AlternateSet", {"glyph": "G"}, [
|
||||
("Alternate", {"glyph": "G.alt1"}, []),
|
||||
("Alternate", {"glyph": "G.alt2"}, [])
|
||||
], self.font)
|
||||
table.fromXML("AlternateSet", {"glyph": "Z"}, [
|
||||
("Alternate", {"glyph": "Z.fina"}, [])
|
||||
], self.font)
|
||||
for name, attrs, content in parseXML(
|
||||
'<AlternateSet glyph="G">'
|
||||
' <Alternate glyph="G.alt1"/>'
|
||||
' <Alternate glyph="G.alt2"/>'
|
||||
'</AlternateSet>'
|
||||
'<AlternateSet glyph="Z">'
|
||||
' <Alternate glyph="Z.fina"/>'
|
||||
'</AlternateSet>'):
|
||||
table.fromXML(name, attrs, content, self.font)
|
||||
self.assertEqual(table.alternates, {
|
||||
"G": ["G.alt1", "G.alt2"],
|
||||
"Z": ["Z.fina"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user