diff --git a/Lib/fontTools/ttLib/tables/otTables_test.py b/Lib/fontTools/ttLib/tables/otTables_test.py
new file mode 100644
index 000000000..cc2b06628
--- /dev/null
+++ b/Lib/fontTools/ttLib/tables/otTables_test.py
@@ -0,0 +1,272 @@
+from __future__ import print_function, division, absolute_import
+from fontTools.misc.py23 import *
+from fontTools.misc.xmlWriter import XMLWriter
+import fontTools.ttLib.tables.otTables as otTables
+import unittest
+
+
+class FakeFont:
+ def __init__(self, glyphs):
+ self.glyphOrder_ = glyphs
+
+ def getGlyphID(self, name):
+ return self.glyphOrder_.index(name)
+
+ def getGlyphName(self, glyphID):
+ return self.glyphOrder_[glyphID]
+
+
+def makeCoverage(glyphs):
+ coverage = otTables.Coverage()
+ coverage.glyphs = glyphs
+ return coverage
+
+
+class SingleSubstTest(unittest.TestCase):
+ def setUp(self):
+ self.glyphs = ".notdef A B C D E a b c d e".split()
+ self.font = FakeFont(self.glyphs)
+
+ def test_postRead_format1(self):
+ table = otTables.SingleSubst()
+ table.Format = 1
+ rawTable = {
+ "Coverage": makeCoverage(["A", "B", "C"]),
+ "DeltaGlyphID": 5
+ }
+ table.postRead(rawTable, self.font)
+ self.assertEqual(table.mapping, {"A": "a", "B": "b", "C": "c"})
+
+ def test_postRead_format2(self):
+ table = otTables.SingleSubst()
+ table.Format = 2
+ rawTable = {
+ "Coverage": makeCoverage(["A", "B", "C"]),
+ "GlyphCount": 3,
+ "Substitute": ["c", "b", "a"]
+ }
+ table.postRead(rawTable, self.font)
+ self.assertEqual(table.mapping, {"A": "c", "B": "b", "C": "a"})
+
+ def test_postRead_formatUnknown(self):
+ table = otTables.SingleSubst()
+ table.Format = 987
+ rawTable = {"Coverage": makeCoverage(["A", "B", "C"])}
+ self.assertRaises(AssertionError, table.postRead, rawTable, self.font)
+
+ def test_preWrite_format1(self):
+ table = otTables.SingleSubst()
+ table.mapping = {"A": "a", "B": "b", "C": "c"}
+ rawTable = table.preWrite(self.font)
+ self.assertEqual(table.Format, 1)
+ self.assertEqual(rawTable["Coverage"].glyphs, ["A", "B", "C"])
+ self.assertEqual(rawTable["DeltaGlyphID"], 5)
+
+ def test_preWrite_format2(self):
+ table = otTables.SingleSubst()
+ table.mapping = {"A": "c", "B": "b", "C": "a"}
+ rawTable = table.preWrite(self.font)
+ self.assertEqual(table.Format, 2)
+ self.assertEqual(rawTable["Coverage"].glyphs, ["A", "B", "C"])
+ self.assertEqual(rawTable["Substitute"], ["c", "b", "a"])
+
+ def test_toXML2(self):
+ writer = XMLWriter(StringIO())
+ table = otTables.SingleSubst()
+ table.mapping = {"A": "a", "B": "b", "C": "c"}
+ table.toXML2(writer, self.font)
+ self.assertEqual(writer.file.getvalue().splitlines()[1:], [
+ '',
+ '',
+ '',
+ ])
+
+ 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)
+ self.assertEqual(table.mapping, {"A": "a", "B": "b", "C": "c"})
+
+
+class LigatureSubstTest(unittest.TestCase):
+ def setUp(self):
+ self.glyphs = ".notdef c f i t c_t f_f f_i f_f_i".split()
+ self.font = FakeFont(self.glyphs)
+
+ def makeLigature(self, s):
+ """'ffi' --> Ligature(LigGlyph='f_f_i', Component=['f', 'f', 'i'])"""
+ lig = otTables.Ligature()
+ lig.Component = list(s)
+ lig.LigGlyph = "_".join(lig.Component)
+ return lig
+
+ def makeLigatures(self, s):
+ """'ffi fi' --> [otTables.Ligature, otTables.Ligature]"""
+ return [self.makeLigature(lig) for lig in s.split()]
+
+ def test_postRead_format1(self):
+ table = otTables.LigatureSubst()
+ table.Format = 1
+ ligs_c = otTables.LigatureSet()
+ ligs_c.Ligature = self.makeLigatures("ct")
+ ligs_f = otTables.LigatureSet()
+ ligs_f.Ligature = self.makeLigatures("ffi ff fi")
+ rawTable = {
+ "Coverage": makeCoverage(["c", "f"]),
+ "LigatureSet": [ligs_c, ligs_f]
+ }
+ table.postRead(rawTable, self.font)
+ self.assertEqual(set(table.ligatures.keys()), {"c", "f"})
+ self.assertEqual(len(table.ligatures["c"]), 1)
+ self.assertEqual(table.ligatures["c"][0].LigGlyph, "c_t")
+ self.assertEqual(table.ligatures["c"][0].Component, ["c", "t"])
+ self.assertEqual(len(table.ligatures["f"]), 3)
+ self.assertEqual(table.ligatures["f"][0].LigGlyph, "f_f_i")
+ self.assertEqual(table.ligatures["f"][0].Component, ["f", "f", "i"])
+ self.assertEqual(table.ligatures["f"][1].LigGlyph, "f_f")
+ self.assertEqual(table.ligatures["f"][1].Component, ["f", "f"])
+ self.assertEqual(table.ligatures["f"][2].LigGlyph, "f_i")
+ self.assertEqual(table.ligatures["f"][2].Component, ["f", "i"])
+
+ def test_postRead_formatUnknown(self):
+ table = otTables.LigatureSubst()
+ table.Format = 987
+ rawTable = {"Coverage": makeCoverage(["f"])}
+ self.assertRaises(AssertionError, table.postRead, rawTable, self.font)
+
+ def test_preWrite_format1(self):
+ table = otTables.LigatureSubst()
+ table.ligatures = {
+ "c": self.makeLigatures("ct"),
+ "f": self.makeLigatures("ffi ff fi")
+ }
+ rawTable = table.preWrite(self.font)
+ self.assertEqual(table.Format, 1)
+ self.assertEqual(rawTable["Coverage"].glyphs, ["c", "f"])
+ [c, f] = rawTable["LigatureSet"]
+ self.assertIsInstance(c, otTables.LigatureSet)
+ self.assertIsInstance(f, otTables.LigatureSet)
+ [ct] = c.Ligature
+ self.assertIsInstance(ct, otTables.Ligature)
+ self.assertEqual(ct.LigGlyph, "c_t")
+ self.assertEqual(ct.Component, ["c", "t"])
+ [ffi, ff, fi] = f.Ligature
+ self.assertIsInstance(ffi, otTables.Ligature)
+ self.assertEqual(ffi.LigGlyph, "f_f_i")
+ self.assertEqual(ffi.Component, ["f", "f", "i"])
+ self.assertIsInstance(ff, otTables.Ligature)
+ self.assertEqual(ff.LigGlyph, "f_f")
+ self.assertEqual(ff.Component, ["f", "f"])
+ self.assertIsInstance(fi, otTables.Ligature)
+ self.assertEqual(fi.LigGlyph, "f_i")
+ self.assertEqual(fi.Component, ["f", "i"])
+
+ def test_toXML2(self):
+ writer = XMLWriter(StringIO())
+ table = otTables.LigatureSubst()
+ table.ligatures = {
+ "c": self.makeLigatures("ct"),
+ "f": self.makeLigatures("ffi ff fi")
+ }
+ table.toXML2(writer, self.font)
+ self.assertEqual(writer.file.getvalue().splitlines()[1:], [
+ '',
+ ' ',
+ '',
+ '',
+ ' ',
+ ' ',
+ ' ',
+ ''
+ ])
+
+ 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)
+ self.assertEqual(set(table.ligatures.keys()), {"f"})
+ [ffi, ff] = table.ligatures["f"]
+ self.assertEqual(ffi.LigGlyph, "f_f_i")
+ self.assertEqual(ffi.Component, ["f", "f", "i"])
+ self.assertEqual(ff.LigGlyph, "f_f")
+ self.assertEqual(ff.Component, ["f", "f"])
+
+
+class AlternateSubstTest(unittest.TestCase):
+ def setUp(self):
+ self.glyphs = ".notdef G G.alt1 G.alt2 Z Z.fina".split()
+ self.font = FakeFont(self.glyphs)
+
+ def makeAlternateSet(self, s):
+ result = otTables.AlternateSet()
+ result.Alternate = s.split()
+ return result
+
+ def test_postRead_format1(self):
+ table = otTables.AlternateSubst()
+ table.Format = 1
+ rawTable = {
+ "Coverage": makeCoverage(["G", "Z"]),
+ "AlternateSet": [
+ self.makeAlternateSet("G.alt1 G.alt2"),
+ self.makeAlternateSet("Z.fina")
+ ]
+ }
+ table.postRead(rawTable, self.font)
+ self.assertEqual(table.alternates, {
+ "G": ["G.alt1", "G.alt2"],
+ "Z": ["Z.fina"]
+ })
+
+ def test_postRead_formatUnknown(self):
+ table = otTables.AlternateSubst()
+ table.Format = 987
+ self.assertRaises(AssertionError, table.postRead, {}, self.font)
+
+ def test_preWrite_format1(self):
+ table = otTables.AlternateSubst()
+ table.alternates = {"G": ["G.alt1", "G.alt2"], "Z": ["Z.fina"]}
+ rawTable = table.preWrite(self.font)
+ self.assertEqual(table.Format, 1)
+ self.assertEqual(rawTable["Coverage"].glyphs, ["G", "Z"])
+ [g, z] = rawTable["AlternateSet"]
+ self.assertIsInstance(g, otTables.AlternateSet)
+ self.assertEqual(g.Alternate, ["G.alt1", "G.alt2"])
+ self.assertIsInstance(z, otTables.AlternateSet)
+ self.assertEqual(z.Alternate, ["Z.fina"])
+
+ def test_toXML2(self):
+ writer = XMLWriter(StringIO())
+ table = otTables.AlternateSubst()
+ table.alternates = {"G": ["G.alt1", "G.alt2"], "Z": ["Z.fina"]}
+ table.toXML2(writer, self.font)
+ self.assertEqual(writer.file.getvalue().splitlines()[1:], [
+ '',
+ ' ',
+ ' ',
+ '',
+ '',
+ ' ',
+ ''
+ ])
+
+ 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)
+ self.assertEqual(table.alternates, {
+ "G": ["G.alt1", "G.alt2"],
+ "Z": ["Z.fina"]
+ })
+
+
+if __name__ == "__main__":
+ unittest.main()