[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 __future__ import print_function, division, absolute_import
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
|
from fontTools.misc.testTools import parseXML
|
||||||
from fontTools.misc.xmlWriter import XMLWriter
|
from fontTools.misc.xmlWriter import XMLWriter
|
||||||
import fontTools.ttLib.tables.otTables as otTables
|
import fontTools.ttLib.tables.otTables as otTables
|
||||||
import unittest
|
import unittest
|
||||||
@ -83,9 +84,11 @@ class SingleSubstTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_fromXML(self):
|
def test_fromXML(self):
|
||||||
table = otTables.SingleSubst()
|
table = otTables.SingleSubst()
|
||||||
table.fromXML("Substitution", {"in": "A", "out": "a"}, [], self.font)
|
for name, attrs, content in parseXML(
|
||||||
table.fromXML("Substitution", {"in": "B", "out": "b"}, [], self.font)
|
'<Substitution in="A" out="a"/>'
|
||||||
table.fromXML("Substitution", {"in": "C", "out": "c"}, [], self.font)
|
'<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"})
|
self.assertEqual(table.mapping, {"A": "a", "B": "b", "C": "c"})
|
||||||
|
|
||||||
|
|
||||||
@ -135,28 +138,30 @@ class MultipleSubstTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_fromXML(self):
|
def test_fromXML(self):
|
||||||
table = otTables.MultipleSubst()
|
table = otTables.MultipleSubst()
|
||||||
table.fromXML("Substitution",
|
for name, attrs, content in parseXML(
|
||||||
{"in": "c_t", "out": "c,t"}, [], self.font)
|
'<Substitution in="c_t" out="c,t"/>'
|
||||||
table.fromXML("Substitution",
|
'<Substitution in="f_f_i" out="f,f,i"/>'):
|
||||||
{"in": "f_f_i", "out": "f,f,i"}, [], self.font)
|
table.fromXML(name, attrs, content, self.font)
|
||||||
self.assertEqual(table.mapping,
|
self.assertEqual(table.mapping,
|
||||||
{'c_t': ['c', 't'], 'f_f_i': ['f', 'f', 'i']})
|
{'c_t': ['c', 't'], 'f_f_i': ['f', 'f', 'i']})
|
||||||
|
|
||||||
def test_fromXML_oldFormat(self):
|
def test_fromXML_oldFormat(self):
|
||||||
table = otTables.MultipleSubst()
|
table = otTables.MultipleSubst()
|
||||||
table.fromXML("Coverage", {}, [
|
for name, attrs, content in parseXML(
|
||||||
("Glyph", {"value": "c_t"}, []),
|
'<Coverage>'
|
||||||
("Glyph", {"value": "f_f_i"}, [])
|
' <Glyph value="c_t"/>'
|
||||||
], self.font)
|
' <Glyph value="f_f_i"/>'
|
||||||
table.fromXML("Sequence", {"index": "0"}, [
|
'</Coverage>'
|
||||||
("Substitute", {"index": "0", "value": "c"}, []),
|
'<Sequence index="0">'
|
||||||
("Substitute", {"index": "1", "value": "t"}, [])
|
' <Substitute index="0" value="c"/>'
|
||||||
], self.font)
|
' <Substitute index="1" value="t"/>'
|
||||||
table.fromXML("Sequence", {"index": "1"}, [
|
'</Sequence>'
|
||||||
("Substitute", {"index": "0", "value": "f"}, []),
|
'<Sequence index="1">'
|
||||||
("Substitute", {"index": "1", "value": "f"}, []),
|
' <Substitute index="0" value="f"/>'
|
||||||
("Substitute", {"index": "2", "value": "i"}, [])
|
' <Substitute index="1" value="f"/>'
|
||||||
], self.font)
|
' <Substitute index="2" value="i"/>'
|
||||||
|
'</Sequence>'):
|
||||||
|
table.fromXML(name, attrs, content, self.font)
|
||||||
self.assertEqual(table.mapping,
|
self.assertEqual(table.mapping,
|
||||||
{'c_t': ['c', 't'], 'f_f_i': ['f', 'f', 'i']})
|
{'c_t': ['c', 't'], 'f_f_i': ['f', 'f', 'i']})
|
||||||
|
|
||||||
@ -255,10 +260,12 @@ class LigatureSubstTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_fromXML(self):
|
def test_fromXML(self):
|
||||||
table = otTables.LigatureSubst()
|
table = otTables.LigatureSubst()
|
||||||
table.fromXML("LigatureSet", {"glyph": "f"}, [
|
for name, attrs, content in parseXML(
|
||||||
("Ligature", {"components": "f,f,i", "glyph": "f_f_i"}, []),
|
'<LigatureSet glyph="f">'
|
||||||
("Ligature", {"components": "f,f", "glyph": "f_f"}, []),
|
' <Ligature components="f,f,i" glyph="f_f_i"/>'
|
||||||
], self.font)
|
' <Ligature components="f,f" glyph="f_f"/>'
|
||||||
|
'</LigatureSet>'):
|
||||||
|
table.fromXML(name, attrs, content, self.font)
|
||||||
self.assertEqual(set(table.ligatures.keys()), {"f"})
|
self.assertEqual(set(table.ligatures.keys()), {"f"})
|
||||||
[ffi, ff] = table.ligatures["f"]
|
[ffi, ff] = table.ligatures["f"]
|
||||||
self.assertEqual(ffi.LigGlyph, "f_f_i")
|
self.assertEqual(ffi.LigGlyph, "f_f_i")
|
||||||
@ -327,13 +334,15 @@ class AlternateSubstTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_fromXML(self):
|
def test_fromXML(self):
|
||||||
table = otTables.AlternateSubst()
|
table = otTables.AlternateSubst()
|
||||||
table.fromXML("AlternateSet", {"glyph": "G"}, [
|
for name, attrs, content in parseXML(
|
||||||
("Alternate", {"glyph": "G.alt1"}, []),
|
'<AlternateSet glyph="G">'
|
||||||
("Alternate", {"glyph": "G.alt2"}, [])
|
' <Alternate glyph="G.alt1"/>'
|
||||||
], self.font)
|
' <Alternate glyph="G.alt2"/>'
|
||||||
table.fromXML("AlternateSet", {"glyph": "Z"}, [
|
'</AlternateSet>'
|
||||||
("Alternate", {"glyph": "Z.fina"}, [])
|
'<AlternateSet glyph="Z">'
|
||||||
], self.font)
|
' <Alternate glyph="Z.fina"/>'
|
||||||
|
'</AlternateSet>'):
|
||||||
|
table.fromXML(name, attrs, content, self.font)
|
||||||
self.assertEqual(table.alternates, {
|
self.assertEqual(table.alternates, {
|
||||||
"G": ["G.alt1", "G.alt2"],
|
"G": ["G.alt1", "G.alt2"],
|
||||||
"Z": ["Z.fina"]
|
"Z": ["Z.fina"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user