2016-01-14 10:27:54 +01:00
|
|
|
from __future__ import print_function, division, absolute_import
|
|
|
|
from __future__ import unicode_literals
|
2016-01-14 12:24:37 +01:00
|
|
|
from fontTools.misc.testTools import getXML
|
2016-01-14 10:27:54 +01:00
|
|
|
from fontTools.otlLib import builder
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
|
|
|
class BuilderTest(unittest.TestCase):
|
2016-01-22 14:12:53 +01:00
|
|
|
GLYPHS = (".notdef space zero one two three four five six "
|
|
|
|
"A B C a b c grave acute cedilla f_f_i f_i c_t").split()
|
2016-01-19 16:54:52 +01:00
|
|
|
GLYPHMAP = {name: num for num, name in enumerate(GLYPHS)}
|
2016-01-14 17:54:47 +01:00
|
|
|
|
|
|
|
ANCHOR1 = builder.buildAnchor(11, -11)
|
|
|
|
ANCHOR2 = builder.buildAnchor(22, -22)
|
|
|
|
ANCHOR3 = builder.buildAnchor(33, -33)
|
|
|
|
|
2016-01-20 19:24:23 +01:00
|
|
|
def __init__(self, methodName):
|
|
|
|
unittest.TestCase.__init__(self, methodName)
|
|
|
|
# Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
|
|
|
|
# and fires deprecation warnings if a program uses the old name.
|
|
|
|
if not hasattr(self, "assertRaisesRegex"):
|
|
|
|
self.assertRaisesRegex = self.assertRaisesRegexp
|
|
|
|
|
2016-01-14 13:08:26 +01:00
|
|
|
def test_buildAnchor_format1(self):
|
|
|
|
anchor = builder.buildAnchor(23, 42)
|
2016-01-14 16:25:28 +01:00
|
|
|
self.assertEqual(getXML(anchor.toXML),
|
2016-01-14 13:08:26 +01:00
|
|
|
'<Anchor Format="1">'
|
|
|
|
' <XCoordinate value="23"/>'
|
|
|
|
' <YCoordinate value="42"/>'
|
|
|
|
'</Anchor>')
|
|
|
|
|
|
|
|
def test_buildAnchor_format2(self):
|
|
|
|
anchor = builder.buildAnchor(23, 42, point=17)
|
2016-01-14 16:25:28 +01:00
|
|
|
self.assertEqual(getXML(anchor.toXML),
|
2016-01-14 13:08:26 +01:00
|
|
|
'<Anchor Format="2">'
|
|
|
|
' <XCoordinate value="23"/>'
|
|
|
|
' <YCoordinate value="42"/>'
|
|
|
|
' <AnchorPoint value="17"/>'
|
|
|
|
'</Anchor>')
|
|
|
|
|
|
|
|
def test_buildAnchor_format3(self):
|
|
|
|
anchor = builder.buildAnchor(
|
|
|
|
23, 42,
|
2016-01-22 19:45:56 +01:00
|
|
|
deviceX=builder.buildDevice({1:1, 0:0}),
|
|
|
|
deviceY=builder.buildDevice({7:7}))
|
2016-01-14 16:25:28 +01:00
|
|
|
self.assertEqual(getXML(anchor.toXML),
|
2016-01-14 13:08:26 +01:00
|
|
|
'<Anchor Format="3">'
|
|
|
|
' <XCoordinate value="23"/>'
|
|
|
|
' <YCoordinate value="42"/>'
|
|
|
|
' <XDeviceTable>'
|
|
|
|
' <StartSize value="0"/>'
|
|
|
|
' <EndSize value="1"/>'
|
|
|
|
' <DeltaFormat value="1"/>'
|
|
|
|
' <DeltaValue value="[0, 1]"/>'
|
|
|
|
' </XDeviceTable>'
|
|
|
|
' <YDeviceTable>'
|
|
|
|
' <StartSize value="7"/>'
|
|
|
|
' <EndSize value="7"/>'
|
|
|
|
' <DeltaFormat value="2"/>'
|
|
|
|
' <DeltaValue value="[7]"/>'
|
|
|
|
' </YDeviceTable>'
|
|
|
|
'</Anchor>')
|
|
|
|
|
2016-01-19 22:38:23 +01:00
|
|
|
def test_buildAttachList(self):
|
|
|
|
attachList = builder.buildAttachList({
|
|
|
|
"zero": [23, 7], "one": [1],
|
|
|
|
}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(attachList.toXML),
|
|
|
|
'<AttachList>'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="zero"/>'
|
|
|
|
' <Glyph value="one"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <!-- GlyphCount=2 -->'
|
|
|
|
' <AttachPoint index="0">'
|
|
|
|
' <!-- PointCount=2 -->'
|
|
|
|
' <PointIndex index="0" value="7"/>'
|
|
|
|
' <PointIndex index="1" value="23"/>'
|
|
|
|
' </AttachPoint>'
|
|
|
|
' <AttachPoint index="1">'
|
|
|
|
' <!-- PointCount=1 -->'
|
|
|
|
' <PointIndex index="0" value="1"/>'
|
|
|
|
' </AttachPoint>'
|
|
|
|
'</AttachList>')
|
|
|
|
|
2016-01-19 23:25:47 +01:00
|
|
|
def test_buildAttachList_empty(self):
|
|
|
|
self.assertIsNone(builder.buildAttachList({}, self.GLYPHMAP))
|
|
|
|
|
|
|
|
def test_buildAttachPoint(self):
|
|
|
|
attachPoint = builder.buildAttachPoint([7, 3])
|
|
|
|
self.assertEqual(getXML(attachPoint.toXML),
|
|
|
|
'<AttachPoint>'
|
|
|
|
' <!-- PointCount=2 -->'
|
|
|
|
' <PointIndex index="0" value="3"/>'
|
|
|
|
' <PointIndex index="1" value="7"/>'
|
|
|
|
'</AttachPoint>')
|
|
|
|
|
2016-01-22 19:54:20 +01:00
|
|
|
def test_buildAttachPoint_empty(self):
|
|
|
|
self.assertIsNone(builder.buildAttachPoint([]))
|
|
|
|
|
|
|
|
def test_buildAttachPoint_duplicate(self):
|
|
|
|
attachPoint = builder.buildAttachPoint([7, 3, 7])
|
|
|
|
self.assertEqual(getXML(attachPoint.toXML),
|
|
|
|
'<AttachPoint>'
|
|
|
|
' <!-- PointCount=2 -->'
|
|
|
|
' <PointIndex index="0" value="3"/>'
|
|
|
|
' <PointIndex index="1" value="7"/>'
|
|
|
|
'</AttachPoint>')
|
|
|
|
|
|
|
|
|
2016-01-22 10:57:03 +01:00
|
|
|
def test_buildBaseArray(self):
|
|
|
|
anchor = builder.buildAnchor
|
|
|
|
baseArray = builder.buildBaseArray({
|
|
|
|
"a": {2: anchor(300, 80)},
|
|
|
|
"c": {1: anchor(300, 80), 2: anchor(300, -20)}
|
|
|
|
}, numMarkClasses=4, glyphMap=self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(baseArray.toXML),
|
|
|
|
'<BaseArray>'
|
|
|
|
' <!-- BaseCount=2 -->'
|
|
|
|
' <BaseRecord index="0">'
|
|
|
|
' <BaseAnchor index="0" empty="1"/>'
|
|
|
|
' <BaseAnchor index="1" empty="1"/>'
|
|
|
|
' <BaseAnchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="80"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="3" empty="1"/>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
' <BaseRecord index="1">'
|
|
|
|
' <BaseAnchor index="0" empty="1"/>'
|
|
|
|
' <BaseAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="80"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="3" empty="1"/>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
'</BaseArray>')
|
|
|
|
|
2016-01-21 17:23:36 +01:00
|
|
|
def test_buildBaseRecord(self):
|
|
|
|
a = builder.buildAnchor
|
|
|
|
rec = builder.buildBaseRecord([a(500, -20), None, a(300, -15)])
|
|
|
|
self.assertEqual(getXML(rec.toXML),
|
|
|
|
'<BaseRecord>'
|
|
|
|
' <BaseAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="1" empty="1"/>'
|
|
|
|
' <BaseAnchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-15"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
'</BaseRecord>')
|
|
|
|
|
2016-01-20 08:23:42 +01:00
|
|
|
def test_buildCaretValueForCoord(self):
|
|
|
|
caret = builder.buildCaretValueForCoord(500)
|
|
|
|
self.assertEqual(getXML(caret.toXML),
|
|
|
|
'<CaretValue Format="1">'
|
|
|
|
' <Coordinate value="500"/>'
|
|
|
|
'</CaretValue>')
|
|
|
|
|
|
|
|
def test_buildCaretValueForPoint(self):
|
|
|
|
caret = builder.buildCaretValueForPoint(23)
|
|
|
|
self.assertEqual(getXML(caret.toXML),
|
|
|
|
'<CaretValue Format="2">'
|
|
|
|
' <CaretValuePoint value="23"/>'
|
|
|
|
'</CaretValue>')
|
|
|
|
|
2016-01-21 15:16:55 +01:00
|
|
|
def test_buildComponentRecord(self):
|
|
|
|
a = builder.buildAnchor
|
|
|
|
rec = builder.buildComponentRecord([a(500, -20), None, a(300, -15)])
|
|
|
|
self.assertEqual(getXML(rec.toXML),
|
|
|
|
'<ComponentRecord>'
|
|
|
|
' <LigatureAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-15"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
'</ComponentRecord>')
|
|
|
|
|
2016-01-22 12:45:29 +01:00
|
|
|
def test_buildComponentRecord_empty(self):
|
|
|
|
self.assertIsNone(builder.buildComponentRecord([]))
|
|
|
|
|
|
|
|
def test_buildComponentRecord_None(self):
|
|
|
|
self.assertIsNone(builder.buildComponentRecord(None))
|
|
|
|
|
2016-01-14 17:10:45 +01:00
|
|
|
def test_buildCoverage(self):
|
|
|
|
cov = builder.buildCoverage({"two", "four"}, {"two": 2, "four": 4})
|
|
|
|
self.assertEqual(getXML(cov.toXML),
|
|
|
|
'<Coverage>'
|
|
|
|
' <Glyph value="two"/>'
|
|
|
|
' <Glyph value="four"/>'
|
|
|
|
'</Coverage>')
|
|
|
|
|
2016-01-14 17:54:47 +01:00
|
|
|
def test_buildCursivePos(self):
|
2016-01-22 19:38:20 +01:00
|
|
|
pos = builder.buildCursivePosSubtable({
|
2016-01-14 17:54:47 +01:00
|
|
|
"two": (self.ANCHOR1, self.ANCHOR2),
|
|
|
|
"four": (self.ANCHOR3, self.ANCHOR1)
|
|
|
|
}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(pos.toXML),
|
|
|
|
'<CursivePos Format="1">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="two"/>'
|
|
|
|
' <Glyph value="four"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <!-- EntryExitCount=2 -->'
|
|
|
|
' <EntryExitRecord index="0">'
|
|
|
|
' <EntryAnchor Format="1">'
|
|
|
|
' <XCoordinate value="11"/>'
|
|
|
|
' <YCoordinate value="-11"/>'
|
|
|
|
' </EntryAnchor>'
|
|
|
|
' <ExitAnchor Format="1">'
|
|
|
|
' <XCoordinate value="22"/>'
|
|
|
|
' <YCoordinate value="-22"/>'
|
|
|
|
' </ExitAnchor>'
|
|
|
|
' </EntryExitRecord>'
|
|
|
|
' <EntryExitRecord index="1">'
|
|
|
|
' <EntryAnchor Format="1">'
|
|
|
|
' <XCoordinate value="33"/>'
|
|
|
|
' <YCoordinate value="-33"/>'
|
|
|
|
' </EntryAnchor>'
|
|
|
|
' <ExitAnchor Format="1">'
|
|
|
|
' <XCoordinate value="11"/>'
|
|
|
|
' <YCoordinate value="-11"/>'
|
|
|
|
' </ExitAnchor>'
|
|
|
|
' </EntryExitRecord>'
|
|
|
|
'</CursivePos>')
|
|
|
|
|
2016-01-14 12:24:37 +01:00
|
|
|
def test_buildDevice_format1(self):
|
2016-01-22 19:45:56 +01:00
|
|
|
device = builder.buildDevice({1:1, 0:0})
|
2016-01-14 16:25:28 +01:00
|
|
|
self.assertEqual(getXML(device.toXML),
|
2016-01-14 12:24:37 +01:00
|
|
|
'<Device>'
|
|
|
|
' <StartSize value="0"/>'
|
|
|
|
' <EndSize value="1"/>'
|
|
|
|
' <DeltaFormat value="1"/>'
|
|
|
|
' <DeltaValue value="[0, 1]"/>'
|
|
|
|
'</Device>')
|
|
|
|
|
|
|
|
def test_buildDevice_format2(self):
|
2016-01-22 19:49:22 +01:00
|
|
|
device = builder.buildDevice({2:2, 0:1, 1:0})
|
2016-01-14 16:25:28 +01:00
|
|
|
self.assertEqual(getXML(device.toXML),
|
2016-01-14 12:24:37 +01:00
|
|
|
'<Device>'
|
2016-01-22 19:49:22 +01:00
|
|
|
' <StartSize value="0"/>'
|
|
|
|
' <EndSize value="2"/>'
|
2016-01-14 12:24:37 +01:00
|
|
|
' <DeltaFormat value="2"/>'
|
|
|
|
' <DeltaValue value="[1, 0, 2]"/>'
|
|
|
|
'</Device>')
|
|
|
|
|
|
|
|
def test_buildDevice_format3(self):
|
2016-01-22 19:45:56 +01:00
|
|
|
device = builder.buildDevice({5:3, 1:77})
|
2016-01-14 16:25:28 +01:00
|
|
|
self.assertEqual(getXML(device.toXML),
|
2016-01-14 12:24:37 +01:00
|
|
|
'<Device>'
|
|
|
|
' <StartSize value="1"/>'
|
|
|
|
' <EndSize value="5"/>'
|
|
|
|
' <DeltaFormat value="3"/>'
|
|
|
|
' <DeltaValue value="[77, 0, 0, 0, 3]"/>'
|
|
|
|
'</Device>')
|
|
|
|
|
2016-01-22 14:12:53 +01:00
|
|
|
def test_buildLigatureArray(self):
|
|
|
|
anchor = builder.buildAnchor
|
|
|
|
ligatureArray = builder.buildLigatureArray({
|
|
|
|
"f_i": [{2: anchor(300, -20)}, {}],
|
|
|
|
"c_t": [{}, {1: anchor(500, 350), 2: anchor(1300, -20)}]
|
|
|
|
}, numMarkClasses=4, glyphMap=self.GLYPHMAP)
|
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(getXML(ligatureArray.toXML),
|
|
|
|
'<LigatureArray>'
|
|
|
|
' <!-- LigatureCount=2 -->'
|
|
|
|
' <LigatureAttach index="0">' # f_i
|
|
|
|
' <!-- ComponentCount=2 -->'
|
|
|
|
' <ComponentRecord index="0">'
|
|
|
|
' <LigatureAnchor index="0" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="3" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' <ComponentRecord index="1">'
|
|
|
|
' <LigatureAnchor index="0" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="2" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="3" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' </LigatureAttach>'
|
|
|
|
' <LigatureAttach index="1">'
|
|
|
|
' <!-- ComponentCount=2 -->'
|
|
|
|
' <ComponentRecord index="0">'
|
|
|
|
' <LigatureAnchor index="0" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="2" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="3" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' <ComponentRecord index="1">'
|
|
|
|
' <LigatureAnchor index="0" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="350"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="1300"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="3" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' </LigatureAttach>'
|
|
|
|
'</LigatureArray>')
|
|
|
|
|
2016-01-22 12:45:29 +01:00
|
|
|
def test_buildLigatureAttach(self):
|
|
|
|
anchor = builder.buildAnchor
|
|
|
|
attach = builder.buildLigatureAttach([
|
|
|
|
[anchor(500, -10), None],
|
|
|
|
[None, anchor(300, -20), None]])
|
|
|
|
self.assertEqual(getXML(attach.toXML),
|
|
|
|
'<LigatureAttach>'
|
|
|
|
' <!-- ComponentCount=2 -->'
|
|
|
|
' <ComponentRecord index="0">'
|
|
|
|
' <LigatureAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-10"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' <ComponentRecord index="1">'
|
|
|
|
' <LigatureAnchor index="0" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="2" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
'</LigatureAttach>')
|
|
|
|
|
|
|
|
def test_buildLigatureAttach_emptyComponents(self):
|
|
|
|
attach = builder.buildLigatureAttach([[], None])
|
|
|
|
self.assertEqual(getXML(attach.toXML),
|
|
|
|
'<LigatureAttach>'
|
|
|
|
' <!-- ComponentCount=2 -->'
|
|
|
|
' <ComponentRecord index="0" empty="1"/>'
|
|
|
|
' <ComponentRecord index="1" empty="1"/>'
|
|
|
|
'</LigatureAttach>')
|
|
|
|
|
|
|
|
def test_buildLigatureAttach_noComponents(self):
|
|
|
|
attach = builder.buildLigatureAttach([])
|
|
|
|
self.assertEqual(getXML(attach.toXML),
|
|
|
|
'<LigatureAttach>'
|
|
|
|
' <!-- ComponentCount=0 -->'
|
|
|
|
'</LigatureAttach>')
|
|
|
|
|
2016-01-20 09:49:09 +01:00
|
|
|
def test_buildLigCaretList(self):
|
|
|
|
carets = builder.buildLigCaretList(
|
|
|
|
{"f_f_i": [300, 600]}, {"c_t": [42]}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(carets.toXML),
|
|
|
|
'<LigCaretList>'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="f_f_i"/>'
|
|
|
|
' <Glyph value="c_t"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <!-- LigGlyphCount=2 -->'
|
|
|
|
' <LigGlyph index="0">'
|
|
|
|
' <!-- CaretCount=2 -->'
|
|
|
|
' <CaretValue index="0" Format="1">'
|
|
|
|
' <Coordinate value="300"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
' <CaretValue index="1" Format="1">'
|
|
|
|
' <Coordinate value="600"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
' </LigGlyph>'
|
|
|
|
' <LigGlyph index="1">'
|
|
|
|
' <!-- CaretCount=1 -->'
|
|
|
|
' <CaretValue index="0" Format="2">'
|
|
|
|
' <CaretValuePoint value="42"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
' </LigGlyph>'
|
|
|
|
'</LigCaretList>')
|
|
|
|
|
|
|
|
def test_buildLigCaretList_bothCoordsAndPointsForSameGlyph(self):
|
|
|
|
carets = builder.buildLigCaretList(
|
|
|
|
{"f_f_i": [300]}, {"f_f_i": [7]}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(carets.toXML),
|
|
|
|
'<LigCaretList>'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="f_f_i"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <!-- LigGlyphCount=1 -->'
|
|
|
|
' <LigGlyph index="0">'
|
|
|
|
' <!-- CaretCount=2 -->'
|
|
|
|
' <CaretValue index="0" Format="1">'
|
|
|
|
' <Coordinate value="300"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
' <CaretValue index="1" Format="2">'
|
|
|
|
' <CaretValuePoint value="7"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
' </LigGlyph>'
|
|
|
|
'</LigCaretList>')
|
|
|
|
|
|
|
|
def test_buildLigCaretList_empty(self):
|
|
|
|
self.assertIsNone(builder.buildLigCaretList({}, {}, self.GLYPHMAP))
|
|
|
|
|
|
|
|
def test_buildLigCaretList_None(self):
|
|
|
|
self.assertIsNone(builder.buildLigCaretList(None, None, self.GLYPHMAP))
|
|
|
|
|
2016-01-20 09:16:31 +01:00
|
|
|
def test_buildLigGlyph_coords(self):
|
|
|
|
lig = builder.buildLigGlyph([500, 800], None)
|
|
|
|
self.assertEqual(getXML(lig.toXML),
|
|
|
|
'<LigGlyph>'
|
|
|
|
' <!-- CaretCount=2 -->'
|
|
|
|
' <CaretValue index="0" Format="1">'
|
|
|
|
' <Coordinate value="500"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
' <CaretValue index="1" Format="1">'
|
|
|
|
' <Coordinate value="800"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
'</LigGlyph>')
|
|
|
|
|
|
|
|
def test_buildLigGlyph_empty(self):
|
|
|
|
self.assertIsNone(builder.buildLigGlyph([], []))
|
|
|
|
|
|
|
|
def test_buildLigGlyph_None(self):
|
|
|
|
self.assertIsNone(builder.buildLigGlyph(None, None))
|
|
|
|
|
|
|
|
def test_buildLigGlyph_points(self):
|
|
|
|
lig = builder.buildLigGlyph(None, [2])
|
|
|
|
self.assertEqual(getXML(lig.toXML),
|
|
|
|
'<LigGlyph>'
|
|
|
|
' <!-- CaretCount=1 -->'
|
|
|
|
' <CaretValue index="0" Format="2">'
|
|
|
|
' <CaretValuePoint value="2"/>'
|
|
|
|
' </CaretValue>'
|
|
|
|
'</LigGlyph>')
|
|
|
|
|
2016-01-20 19:24:23 +01:00
|
|
|
def test_buildLookup(self):
|
2016-01-22 19:32:45 +01:00
|
|
|
s1 = builder.buildSingleSubstSubtable({"one": "two"})
|
|
|
|
s2 = builder.buildSingleSubstSubtable({"three": "four"})
|
2016-01-20 19:24:23 +01:00
|
|
|
lookup = builder.buildLookup([s1, s2], flags=7)
|
|
|
|
self.assertEqual(getXML(lookup.toXML),
|
|
|
|
'<Lookup>'
|
|
|
|
' <!-- LookupType=1 -->'
|
|
|
|
' <LookupFlag value="7"/>'
|
|
|
|
' <!-- SubTableCount=2 -->'
|
|
|
|
' <SingleSubst index="0">'
|
|
|
|
' <Substitution in="one" out="two"/>'
|
|
|
|
' </SingleSubst>'
|
|
|
|
' <SingleSubst index="1">'
|
|
|
|
' <Substitution in="three" out="four"/>'
|
|
|
|
' </SingleSubst>'
|
|
|
|
'</Lookup>')
|
|
|
|
|
|
|
|
def test_buildLookup_badFlags(self):
|
2016-01-22 19:32:45 +01:00
|
|
|
s = builder.buildSingleSubstSubtable({"one": "two"})
|
2016-01-20 19:24:23 +01:00
|
|
|
self.assertRaisesRegex(
|
|
|
|
AssertionError, "if markFilterSet is None, "
|
|
|
|
"flags must not set LOOKUP_FLAG_USE_MARK_FILTERING_SET; "
|
|
|
|
"flags=0x0010",
|
|
|
|
builder.buildLookup, [s],
|
|
|
|
builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET, None)
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
AssertionError, "if markFilterSet is not None, "
|
|
|
|
"flags must set LOOKUP_FLAG_USE_MARK_FILTERING_SET; "
|
|
|
|
"flags=0x0004",
|
|
|
|
builder.buildLookup, [s],
|
|
|
|
builder.LOOKUP_FLAG_IGNORE_LIGATURES, 777)
|
|
|
|
|
|
|
|
def test_buildLookup_conflictingSubtableTypes(self):
|
2016-01-22 19:32:45 +01:00
|
|
|
s1 = builder.buildSingleSubstSubtable({"one": "two"})
|
|
|
|
s2 = builder.buildAlternateSubstSubtable({"one": ["two", "three"]})
|
2016-01-20 19:24:23 +01:00
|
|
|
self.assertRaisesRegex(
|
|
|
|
AssertionError, "all subtables must have the same LookupType",
|
|
|
|
builder.buildLookup, [s1, s2])
|
|
|
|
|
|
|
|
def test_buildLookup_noSubtables(self):
|
|
|
|
self.assertIsNone(builder.buildLookup([]))
|
|
|
|
self.assertIsNone(builder.buildLookup(None))
|
2016-01-22 19:38:20 +01:00
|
|
|
self.assertIsNone(builder.buildLookup([None]))
|
|
|
|
self.assertIsNone(builder.buildLookup([None, None]))
|
2016-01-20 19:24:23 +01:00
|
|
|
|
|
|
|
def test_buildLookup_markFilterSet(self):
|
2016-01-22 19:32:45 +01:00
|
|
|
s = builder.buildSingleSubstSubtable({"one": "two"})
|
2016-01-20 19:24:23 +01:00
|
|
|
flags = (builder.LOOKUP_FLAG_RIGHT_TO_LEFT |
|
|
|
|
builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET)
|
|
|
|
lookup = builder.buildLookup([s], flags, markFilterSet=999)
|
|
|
|
self.assertEqual(getXML(lookup.toXML),
|
|
|
|
'<Lookup>'
|
|
|
|
' <!-- LookupType=1 -->'
|
|
|
|
' <LookupFlag value="17"/>'
|
|
|
|
' <!-- SubTableCount=1 -->'
|
|
|
|
' <SingleSubst index="0">'
|
|
|
|
' <Substitution in="one" out="two"/>'
|
|
|
|
' </SingleSubst>'
|
|
|
|
' <MarkFilteringSet value="999"/>'
|
|
|
|
'</Lookup>')
|
|
|
|
|
2016-01-21 16:23:55 +01:00
|
|
|
def test_buildMarkArray(self):
|
|
|
|
markArray = builder.buildMarkArray({
|
|
|
|
"acute": (7, builder.buildAnchor(300, 800)),
|
|
|
|
"grave": (2, builder.buildAnchor(10, 80))
|
|
|
|
}, self.GLYPHMAP)
|
|
|
|
self.assertLess(self.GLYPHMAP["grave"], self.GLYPHMAP["acute"])
|
|
|
|
self.assertEqual(getXML(markArray.toXML),
|
|
|
|
'<MarkArray>'
|
|
|
|
' <!-- MarkCount=2 -->'
|
|
|
|
' <MarkRecord index="0">'
|
|
|
|
' <Class value="2"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="10"/>'
|
|
|
|
' <YCoordinate value="80"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' <MarkRecord index="1">'
|
|
|
|
' <Class value="7"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="800"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
'</MarkArray>')
|
|
|
|
|
2016-01-22 11:53:34 +01:00
|
|
|
def test_buildMarkBasePosSubtable(self):
|
|
|
|
anchor = builder.buildAnchor
|
|
|
|
marks = {
|
|
|
|
"acute": (0, anchor(300, 700)),
|
|
|
|
"cedilla": (1, anchor(300, -100)),
|
|
|
|
"grave": (0, anchor(300, 700))
|
|
|
|
}
|
|
|
|
bases = {
|
|
|
|
# Make sure we can handle missing entries.
|
|
|
|
"A": {}, # no entry for any markClass
|
|
|
|
"B": {0: anchor(500, 900)}, # only markClass 0 specified
|
|
|
|
"C": {1: anchor(500, -10)}, # only markClass 1 specified
|
|
|
|
|
|
|
|
"a": {0: anchor(500, 400), 1: anchor(500, -20)},
|
|
|
|
"b": {0: anchor(500, 800), 1: anchor(500, -20)}
|
|
|
|
}
|
|
|
|
table = builder.buildMarkBasePosSubtable(marks, bases, self.GLYPHMAP)
|
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(getXML(table.toXML),
|
|
|
|
'<MarkBasePos Format="1">'
|
|
|
|
' <MarkCoverage>'
|
|
|
|
' <Glyph value="grave"/>'
|
|
|
|
' <Glyph value="acute"/>'
|
|
|
|
' <Glyph value="cedilla"/>'
|
|
|
|
' </MarkCoverage>'
|
|
|
|
' <BaseCoverage>'
|
|
|
|
' <Glyph value="A"/>'
|
|
|
|
' <Glyph value="B"/>'
|
|
|
|
' <Glyph value="C"/>'
|
|
|
|
' <Glyph value="a"/>'
|
|
|
|
' <Glyph value="b"/>'
|
|
|
|
' </BaseCoverage>'
|
|
|
|
' <!-- ClassCount=2 -->'
|
|
|
|
' <MarkArray>'
|
|
|
|
' <!-- MarkCount=3 -->'
|
|
|
|
' <MarkRecord index="0">' # grave
|
|
|
|
' <Class value="0"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="700"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' <MarkRecord index="1">' # acute
|
|
|
|
' <Class value="0"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="700"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' <MarkRecord index="2">' # cedilla
|
|
|
|
' <Class value="1"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-100"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' </MarkArray>'
|
|
|
|
' <BaseArray>'
|
|
|
|
' <!-- BaseCount=5 -->'
|
|
|
|
' <BaseRecord index="0">' # A
|
|
|
|
' <BaseAnchor index="0" empty="1"/>'
|
|
|
|
' <BaseAnchor index="1" empty="1"/>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
' <BaseRecord index="1">' # B
|
|
|
|
' <BaseAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="900"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="1" empty="1"/>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
' <BaseRecord index="2">' # C
|
|
|
|
' <BaseAnchor index="0" empty="1"/>'
|
|
|
|
' <BaseAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-10"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
' <BaseRecord index="3">' # a
|
|
|
|
' <BaseAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="400"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
' <BaseRecord index="4">' # b
|
|
|
|
' <BaseAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="800"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' <BaseAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </BaseAnchor>'
|
|
|
|
' </BaseRecord>'
|
|
|
|
' </BaseArray>'
|
|
|
|
'</MarkBasePos>')
|
|
|
|
|
2016-01-20 11:28:33 +01:00
|
|
|
def test_buildMarkGlyphSetsDef(self):
|
|
|
|
marksets = builder.buildMarkGlyphSetsDef(
|
|
|
|
[{"acute", "grave"}, {"cedilla", "grave"}], self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(marksets.toXML),
|
|
|
|
'<MarkGlyphSetsDef>'
|
|
|
|
' <MarkSetTableFormat value="1"/>'
|
|
|
|
' <!-- MarkSetCount=2 -->'
|
|
|
|
' <Coverage index="0">'
|
|
|
|
' <Glyph value="grave"/>'
|
|
|
|
' <Glyph value="acute"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <Coverage index="1">'
|
|
|
|
' <Glyph value="grave"/>'
|
|
|
|
' <Glyph value="cedilla"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
'</MarkGlyphSetsDef>')
|
|
|
|
|
|
|
|
def test_buildMarkGlyphSetsDef_empty(self):
|
|
|
|
self.assertIsNone(builder.buildMarkGlyphSetsDef([], self.GLYPHMAP))
|
|
|
|
|
|
|
|
def test_buildMarkGlyphSetsDef_None(self):
|
|
|
|
self.assertIsNone(builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP))
|
|
|
|
|
2016-01-22 14:50:17 +01:00
|
|
|
def test_buildMarkLigPosSubtable(self):
|
|
|
|
anchor = builder.buildAnchor
|
|
|
|
marks = {
|
|
|
|
"acute": (0, anchor(300, 700)),
|
|
|
|
"cedilla": (1, anchor(300, -100)),
|
|
|
|
"grave": (0, anchor(300, 700))
|
|
|
|
}
|
|
|
|
bases = {
|
|
|
|
"f_i": [{}, {0: anchor(200, 400)}], # nothing on f; only 1 on i
|
|
|
|
"c_t": [
|
|
|
|
{0: anchor(500, 600), 1: anchor(500, -20)}, # c
|
|
|
|
{0: anchor(1300, 800), 1: anchor(1300, -20)} # t
|
|
|
|
]
|
|
|
|
}
|
|
|
|
table = builder.buildMarkLigPosSubtable(marks, bases, self.GLYPHMAP)
|
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(getXML(table.toXML),
|
|
|
|
'<MarkLigPos Format="1">'
|
|
|
|
' <MarkCoverage>'
|
|
|
|
' <Glyph value="grave"/>'
|
|
|
|
' <Glyph value="acute"/>'
|
|
|
|
' <Glyph value="cedilla"/>'
|
|
|
|
' </MarkCoverage>'
|
|
|
|
' <LigatureCoverage>'
|
|
|
|
' <Glyph value="f_i"/>'
|
|
|
|
' <Glyph value="c_t"/>'
|
|
|
|
' </LigatureCoverage>'
|
|
|
|
' <!-- ClassCount=2 -->'
|
|
|
|
' <MarkArray>'
|
|
|
|
' <!-- MarkCount=3 -->'
|
|
|
|
' <MarkRecord index="0">'
|
|
|
|
' <Class value="0"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="700"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' <MarkRecord index="1">'
|
|
|
|
' <Class value="0"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="700"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' <MarkRecord index="2">'
|
|
|
|
' <Class value="1"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-100"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
' </MarkRecord>'
|
|
|
|
' </MarkArray>'
|
|
|
|
' <LigatureArray>'
|
|
|
|
' <!-- LigatureCount=2 -->'
|
|
|
|
' <LigatureAttach index="0">'
|
|
|
|
' <!-- ComponentCount=2 -->'
|
|
|
|
' <ComponentRecord index="0">'
|
|
|
|
' <LigatureAnchor index="0" empty="1"/>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' <ComponentRecord index="1">'
|
|
|
|
' <LigatureAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="200"/>'
|
|
|
|
' <YCoordinate value="400"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="1" empty="1"/>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' </LigatureAttach>'
|
|
|
|
' <LigatureAttach index="1">'
|
|
|
|
' <!-- ComponentCount=2 -->'
|
|
|
|
' <ComponentRecord index="0">'
|
|
|
|
' <LigatureAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="600"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' <ComponentRecord index="1">'
|
|
|
|
' <LigatureAnchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="1300"/>'
|
|
|
|
' <YCoordinate value="800"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' <LigatureAnchor index="1" Format="1">'
|
|
|
|
' <XCoordinate value="1300"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </LigatureAnchor>'
|
|
|
|
' </ComponentRecord>'
|
|
|
|
' </LigatureAttach>'
|
|
|
|
' </LigatureArray>'
|
|
|
|
'</MarkLigPos>')
|
|
|
|
|
2016-01-21 11:29:32 +01:00
|
|
|
def test_buildMarkRecord(self):
|
|
|
|
rec = builder.buildMarkRecord(17, builder.buildAnchor(500, -20))
|
|
|
|
self.assertEqual(getXML(rec.toXML),
|
|
|
|
'<MarkRecord> '
|
|
|
|
' <Class value="17"/>'
|
|
|
|
' <MarkAnchor Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </MarkAnchor>'
|
|
|
|
'</MarkRecord>')
|
|
|
|
|
2016-01-21 13:05:36 +01:00
|
|
|
def test_buildMark2Record(self):
|
|
|
|
a = builder.buildAnchor
|
|
|
|
rec = builder.buildMark2Record([a(500, -20), None, a(300, -15)])
|
|
|
|
self.assertEqual(getXML(rec.toXML),
|
|
|
|
'<Mark2Record>'
|
|
|
|
' <Mark2Anchor index="0" Format="1">'
|
|
|
|
' <XCoordinate value="500"/>'
|
|
|
|
' <YCoordinate value="-20"/>'
|
|
|
|
' </Mark2Anchor>'
|
|
|
|
' <Mark2Anchor index="1" empty="1"/>'
|
|
|
|
' <Mark2Anchor index="2" Format="1">'
|
|
|
|
' <XCoordinate value="300"/>'
|
|
|
|
' <YCoordinate value="-15"/>'
|
|
|
|
' </Mark2Anchor>'
|
|
|
|
'</Mark2Record>')
|
|
|
|
|
2016-01-19 14:22:28 +01:00
|
|
|
def test_buildSinglePos(self):
|
|
|
|
subtables = builder.buildSinglePos({
|
|
|
|
"one": builder.buildValue({"XPlacement": 500}),
|
|
|
|
"two": builder.buildValue({"XPlacement": 500}),
|
|
|
|
"three": builder.buildValue({"XPlacement": 200}),
|
|
|
|
"four": builder.buildValue({"XPlacement": 400}),
|
|
|
|
"five": builder.buildValue({"XPlacement": 500}),
|
|
|
|
"six": builder.buildValue({"YPlacement": -6}),
|
|
|
|
}, self.GLYPHMAP)
|
2016-01-19 15:38:33 +01:00
|
|
|
self.assertEqual(''.join([getXML(t.toXML) for t in subtables]),
|
2016-01-19 14:22:28 +01:00
|
|
|
'<SinglePos Format="1">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="one"/>'
|
|
|
|
' <Glyph value="two"/>'
|
|
|
|
' <Glyph value="five"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <ValueFormat value="1"/>'
|
|
|
|
' <Value XPlacement="500"/>'
|
|
|
|
'</SinglePos>'
|
|
|
|
'<SinglePos Format="2">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="three"/>'
|
|
|
|
' <Glyph value="four"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <ValueFormat value="1"/>'
|
|
|
|
' <!-- ValueCount=2 -->'
|
|
|
|
' <Value index="0" XPlacement="200"/>'
|
|
|
|
' <Value index="1" XPlacement="400"/>'
|
|
|
|
'</SinglePos>'
|
|
|
|
'<SinglePos Format="1">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="six"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <ValueFormat value="2"/>'
|
|
|
|
' <Value YPlacement="-6"/>'
|
|
|
|
'</SinglePos>')
|
|
|
|
|
2016-01-19 16:49:54 +01:00
|
|
|
def test_buildSinglePos_ValueFormat0(self):
|
|
|
|
subtables = builder.buildSinglePos({
|
|
|
|
"zero": builder.buildValue({})
|
|
|
|
}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(''.join([getXML(t.toXML) for t in subtables]),
|
|
|
|
'<SinglePos Format="1">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="zero"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <ValueFormat value="0"/>'
|
|
|
|
'</SinglePos>')
|
|
|
|
|
2016-01-19 15:38:33 +01:00
|
|
|
def test_buildSinglePosSubtable_format1(self):
|
|
|
|
subtable = builder.buildSinglePosSubtable({
|
|
|
|
"one": builder.buildValue({"XPlacement": 777}),
|
|
|
|
"two": builder.buildValue({"XPlacement": 777}),
|
|
|
|
}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(subtable.toXML),
|
|
|
|
'<SinglePos Format="1">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="one"/>'
|
|
|
|
' <Glyph value="two"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <ValueFormat value="1"/>'
|
|
|
|
' <Value XPlacement="777"/>'
|
|
|
|
'</SinglePos>')
|
|
|
|
|
|
|
|
def test_buildSinglePosSubtable_format2(self):
|
|
|
|
subtable = builder.buildSinglePosSubtable({
|
|
|
|
"one": builder.buildValue({"XPlacement": 777}),
|
|
|
|
"two": builder.buildValue({"YPlacement": -888}),
|
|
|
|
}, self.GLYPHMAP)
|
|
|
|
self.assertEqual(getXML(subtable.toXML),
|
|
|
|
'<SinglePos Format="2">'
|
|
|
|
' <Coverage>'
|
|
|
|
' <Glyph value="one"/>'
|
|
|
|
' <Glyph value="two"/>'
|
|
|
|
' </Coverage>'
|
|
|
|
' <ValueFormat value="3"/>'
|
|
|
|
' <!-- ValueCount=2 -->'
|
|
|
|
' <Value index="0" XPlacement="777"/>'
|
|
|
|
' <Value index="1" YPlacement="-888"/>'
|
|
|
|
'</SinglePos>')
|
|
|
|
|
2016-01-14 16:25:28 +01:00
|
|
|
def test_buildValue(self):
|
|
|
|
value = builder.buildValue({"XPlacement": 7, "YPlacement": 23})
|
|
|
|
func = lambda writer, font: value.toXML(writer, font, valueName="Val")
|
|
|
|
self.assertEqual(getXML(func),
|
|
|
|
'<Val XPlacement="7" YPlacement="23"/>')
|
|
|
|
|
2016-01-14 10:27:54 +01:00
|
|
|
def test_getLigatureKey(self):
|
|
|
|
components = lambda s: [tuple(word) for word in s.split()]
|
|
|
|
c = components("fi fl ff ffi fff")
|
2016-01-14 12:32:32 +00:00
|
|
|
c.sort(key=builder._getLigatureKey)
|
2016-01-14 12:24:37 +01:00
|
|
|
self.assertEqual(c, components("fff ffi ff fi fl"))
|
2016-01-14 10:27:54 +01:00
|
|
|
|
2016-01-19 14:22:28 +01:00
|
|
|
def test_getSinglePosValueKey(self):
|
2016-01-22 19:45:56 +01:00
|
|
|
device = builder.buildDevice({10:1, 11:3})
|
2016-01-19 14:22:28 +01:00
|
|
|
a1 = builder.buildValue({"XPlacement": 500, "XPlaDevice": device})
|
|
|
|
a2 = builder.buildValue({"XPlacement": 500, "XPlaDevice": device})
|
|
|
|
b = builder.buildValue({"XPlacement": 500})
|
|
|
|
keyA1 = builder._getSinglePosValueKey(a1)
|
|
|
|
keyA2 = builder._getSinglePosValueKey(a1)
|
|
|
|
keyB = builder._getSinglePosValueKey(b)
|
|
|
|
self.assertEqual(keyA1, keyA2)
|
|
|
|
self.assertEqual(hash(keyA1), hash(keyA2))
|
|
|
|
self.assertNotEqual(keyA1, keyB)
|
|
|
|
self.assertNotEqual(hash(keyA1), hash(keyB))
|
|
|
|
|
2016-01-14 10:27:54 +01:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main()
|