aboutsummaryrefslogtreecommitdiff
path: root/Tests/feaLib
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/feaLib')
-rw-r--r--Tests/feaLib/STAT2.fea4
-rw-r--r--Tests/feaLib/builder_test.py213
-rw-r--r--Tests/feaLib/data/GPOS_2.ttx1
-rw-r--r--Tests/feaLib/data/GPOS_2b.ttx5
-rw-r--r--Tests/feaLib/data/GPOS_4.fea10
-rw-r--r--Tests/feaLib/data/GPOS_5.fea29
-rw-r--r--Tests/feaLib/data/GPOS_6.fea7
-rw-r--r--Tests/feaLib/data/PairPosSubtable.ttx5
-rw-r--r--Tests/feaLib/data/STAT_bad.fea96
-rw-r--r--Tests/feaLib/data/STAT_test.fea109
-rw-r--r--Tests/feaLib/data/STAT_test.ttx228
-rw-r--r--Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea84
-rw-r--r--Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx225
-rw-r--r--Tests/feaLib/data/bug453.fea6
-rw-r--r--Tests/feaLib/data/bug633.ttx1
-rw-r--r--Tests/feaLib/data/size2.ttx4
-rw-r--r--Tests/feaLib/data/spec6b_ii.ttx1
-rw-r--r--Tests/feaLib/data/spec6d2.fea10
-rw-r--r--Tests/feaLib/data/spec6e.fea9
-rw-r--r--Tests/feaLib/data/spec6f.fea3
-rw-r--r--Tests/feaLib/data/spec6h_ii.fea6
-rw-r--r--Tests/feaLib/lexer_test.py9
-rw-r--r--Tests/feaLib/parser_test.py70
23 files changed, 1100 insertions, 35 deletions
diff --git a/Tests/feaLib/STAT2.fea b/Tests/feaLib/STAT2.fea
new file mode 100644
index 00000000..2595a9a4
--- /dev/null
+++ b/Tests/feaLib/STAT2.fea
@@ -0,0 +1,4 @@
+table STAT {
+ ElidedFallbackName { name "Roman"; };
+ DesignAxis zonk 0 { name "Zonkey"; };'
+} STAT;
diff --git a/Tests/feaLib/builder_test.py b/Tests/feaLib/builder_test.py
index 279e8ca8..0a55239c 100644
--- a/Tests/feaLib/builder_test.py
+++ b/Tests/feaLib/builder_test.py
@@ -1,4 +1,3 @@
-from fontTools.misc.py23 import *
from fontTools.misc.loggingTools import CapturingLogHandler
from fontTools.feaLib.builder import Builder, addOpenTypeFeatures, \
addOpenTypeFeaturesFromString
@@ -8,7 +7,9 @@ from fontTools.feaLib.parser import Parser
from fontTools.feaLib import ast
from fontTools.feaLib.lexer import Lexer
import difflib
+from io import StringIO
import os
+import re
import shutil
import sys
import tempfile
@@ -73,7 +74,7 @@ class BuilderTest(unittest.TestCase):
LigatureSubtable AlternateSubtable MultipleSubstSubtable
SingleSubstSubtable aalt_chain_contextual_subst AlternateChained
MultipleLookupsPerGlyph MultipleLookupsPerGlyph2 GSUB_6_formats
- GSUB_5_formats delete_glyph
+ GSUB_5_formats delete_glyph STAT_test STAT_test_elidedFallbackNameID
""".split()
def __init__(self, methodName):
@@ -118,7 +119,7 @@ class BuilderTest(unittest.TestCase):
def expect_ttx(self, font, expected_ttx, replace=None):
path = self.temp_path(suffix=".ttx")
font.saveXML(path, tables=['head', 'name', 'BASE', 'GDEF', 'GSUB',
- 'GPOS', 'OS/2', 'hhea', 'vhea'])
+ 'GPOS', 'OS/2', 'STAT', 'hhea', 'vhea'])
actual = self.read_ttx(path)
expected = self.read_ttx(expected_ttx)
if replace:
@@ -141,10 +142,15 @@ class BuilderTest(unittest.TestCase):
feapath = self.getpath("%s.fea" % name)
addOpenTypeFeatures(font, feapath)
self.expect_ttx(font, self.getpath("%s.ttx" % name))
- # Make sure we can produce binary OpenType tables, not just XML.
+ # Check that:
+ # 1) tables do compile (only G* tables as long as we have a mock font)
+ # 2) dumping after save-reload yields the same TTX dump as before
for tag in ('GDEF', 'GSUB', 'GPOS'):
if tag in font:
- font[tag].compile(font)
+ data = font[tag].compile(font)
+ font[tag].decompile(data, font)
+ self.expect_ttx(font, self.getpath("%s.ttx" % name))
+ # Optionally check a debug dump.
debugttx = self.getpath("%s-debug.ttx" % name)
if os.path.exists(debugttx):
addOpenTypeFeatures(font, feapath, debug=True)
@@ -463,6 +469,201 @@ class BuilderTest(unittest.TestCase):
"} test;"
)
+ def test_STAT_elidedfallbackname_already_defined(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'ElidedFallbackName is already set.',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' ElidedFallbackNameID 256;'
+ '} STAT;')
+
+ def test_STAT_elidedfallbackname_set_twice(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'ElidedFallbackName is already set.',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' ElidedFallbackName { name "Italic"; };'
+ '} STAT;')
+
+ def test_STAT_elidedfallbacknameID_already_defined(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'ElidedFallbackNameID is already set.',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackNameID 256;'
+ ' ElidedFallbackName { name "Roman"; };'
+ '} STAT;')
+
+ def test_STAT_elidedfallbacknameID_not_in_name_table(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'ElidedFallbackNameID 256 points to a nameID that does not '
+ 'exist in the "name" table',
+ self.build,
+ 'table name {'
+ ' nameid 257 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackNameID 256;'
+ ' DesignAxis opsz 1 { name "Optical Size"; };'
+ '} STAT;')
+
+ def test_STAT_design_axis_name(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'Expected "name"',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' DesignAxis opsz 0 { badtag "Optical Size"; };'
+ '} STAT;')
+
+ def test_STAT_duplicate_design_axis_name(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'DesignAxis already defined for tag "opsz".',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' DesignAxis opsz 0 { name "Optical Size"; };'
+ ' DesignAxis opsz 1 { name "Optical Size"; };'
+ '} STAT;')
+
+ def test_STAT_design_axis_duplicate_order(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ "DesignAxis already defined for axis number 0.",
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' DesignAxis opsz 0 { name "Optical Size"; };'
+ ' DesignAxis wdth 0 { name "Width"; };'
+ ' AxisValue {'
+ ' location opsz 8;'
+ ' location wdth 400;'
+ ' name "Caption";'
+ ' };'
+ '} STAT;')
+
+ def test_STAT_undefined_tag(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'DesignAxis not defined for wdth.',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' DesignAxis opsz 0 { name "Optical Size"; };'
+ ' AxisValue { '
+ ' location wdth 125; '
+ ' name "Wide"; '
+ ' };'
+ '} STAT;')
+
+ def test_STAT_axis_value_format4(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'Axis tag wdth already defined.',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' DesignAxis opsz 0 { name "Optical Size"; };'
+ ' DesignAxis wdth 1 { name "Width"; };'
+ ' DesignAxis wght 2 { name "Weight"; };'
+ ' AxisValue { '
+ ' location opsz 8; '
+ ' location wdth 125; '
+ ' location wdth 125; '
+ ' location wght 500; '
+ ' name "Caption Medium Wide"; '
+ ' };'
+ '} STAT;')
+
+ def test_STAT_duplicate_axis_value_record(self):
+ # Test for Duplicate AxisValueRecords even when the definition order
+ # is different.
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'An AxisValueRecord with these values is already defined.',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; };'
+ ' DesignAxis opsz 0 { name "Optical Size"; };'
+ ' DesignAxis wdth 1 { name "Width"; };'
+ ' AxisValue {'
+ ' location opsz 8;'
+ ' location wdth 400;'
+ ' name "Caption";'
+ ' };'
+ ' AxisValue {'
+ ' location wdth 400;'
+ ' location opsz 8;'
+ ' name "Caption";'
+ ' };'
+ '} STAT;')
+
+ def test_STAT_axis_value_missing_location(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'Expected "Axis location"',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; '
+ '};'
+ ' DesignAxis opsz 0 { name "Optical Size"; };'
+ ' AxisValue { '
+ ' name "Wide"; '
+ ' };'
+ '} STAT;')
+
+ def test_STAT_invalid_location_tag(self):
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'Tags cannot be longer than 4 characters',
+ self.build,
+ 'table name {'
+ ' nameid 256 "Roman"; '
+ '} name;'
+ 'table STAT {'
+ ' ElidedFallbackName { name "Roman"; '
+ ' name 3 1 0x0411 "ローマン"; }; '
+ ' DesignAxis width 0 { name "Width"; };'
+ '} STAT;')
+
def test_extensions(self):
class ast_BaseClass(ast.MarkClass):
def asFea(self, indent=""):
@@ -574,7 +775,7 @@ class BuilderTest(unittest.TestCase):
self.assertRaises(NotImplementedError, self.build, "", tables={"FOO"})
def test_build_pre_parsed_ast_featurefile(self):
- f = UnicodeIO("feature liga {sub f i by f_i;} liga;")
+ f = StringIO("feature liga {sub f i by f_i;} liga;")
tree = Parser(f).parse()
font = makeTTFont()
addOpenTypeFeatures(font, tree)
diff --git a/Tests/feaLib/data/GPOS_2.ttx b/Tests/feaLib/data/GPOS_2.ttx
index 84dc8195..c9a6c146 100644
--- a/Tests/feaLib/data/GPOS_2.ttx
+++ b/Tests/feaLib/data/GPOS_2.ttx
@@ -76,6 +76,7 @@
<!-- Class2Count=2 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="-26"/>
diff --git a/Tests/feaLib/data/GPOS_2b.ttx b/Tests/feaLib/data/GPOS_2b.ttx
index 40f458f2..8a892c1e 100644
--- a/Tests/feaLib/data/GPOS_2b.ttx
+++ b/Tests/feaLib/data/GPOS_2b.ttx
@@ -50,6 +50,7 @@
<!-- Class2Count=2 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="1"/>
@@ -79,6 +80,7 @@
<!-- Class2Count=3 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="4"/>
@@ -89,8 +91,10 @@
</Class1Record>
<Class1Record index="1">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="2">
<Value1 XAdvance="2"/>
@@ -114,6 +118,7 @@
<!-- Class2Count=2 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XPlacement="0" YPlacement="0" XAdvance="0" YAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XPlacement="5" YPlacement="5" XAdvance="5" YAdvance="5"/>
diff --git a/Tests/feaLib/data/GPOS_4.fea b/Tests/feaLib/data/GPOS_4.fea
index cfd2d757..7c90ab63 100644
--- a/Tests/feaLib/data/GPOS_4.fea
+++ b/Tests/feaLib/data/GPOS_4.fea
@@ -6,7 +6,11 @@ markClass [cedilla] <anchor 222 22> @BOTTOM_MARKS;
markClass [ogonek] <anchor 333 33> @SIDE_MARKS;
feature test {
- pos base a <anchor 11 1> mark @TOP_MARKS <anchor 12 -1> mark @BOTTOM_MARKS;
- pos base [b c] <anchor 22 -2> mark @BOTTOM_MARKS;
- pos base d <anchor 33 3> mark @SIDE_MARKS;
+ pos base a
+ <anchor 11 1> mark @TOP_MARKS
+ <anchor 12 -1> mark @BOTTOM_MARKS;
+ pos base [b c]
+ <anchor 22 -2> mark @BOTTOM_MARKS;
+ pos base d
+ <anchor 33 3> mark @SIDE_MARKS;
} test;
diff --git a/Tests/feaLib/data/GPOS_5.fea b/Tests/feaLib/data/GPOS_5.fea
index b116539a..a8f8536e 100644
--- a/Tests/feaLib/data/GPOS_5.fea
+++ b/Tests/feaLib/data/GPOS_5.fea
@@ -5,14 +5,29 @@ markClass [ogonek] <anchor 800 -10> @OGONEK;
feature test {
- pos ligature [c_t s_t] <anchor 500 800> mark @TOP_MARKS <anchor 500 -200> mark @BOTTOM_MARKS
- ligComponent <anchor 1500 800> mark @TOP_MARKS <anchor 1500 -200> mark @BOTTOM_MARKS <anchor 1550 0> mark @OGONEK;
+ pos ligature [c_t s_t]
+ <anchor 500 800> mark @TOP_MARKS
+ <anchor 500 -200> mark @BOTTOM_MARKS
+ ligComponent
+ <anchor 1500 800> mark @TOP_MARKS
+ <anchor 1500 -200> mark @BOTTOM_MARKS
+ <anchor 1550 0> mark @OGONEK;
- pos ligature f_l <anchor 300 800> mark @TOP_MARKS <anchor 300 -200> mark @BOTTOM_MARKS
- ligComponent <anchor 600 800> mark @TOP_MARKS <anchor 600 -200> mark @BOTTOM_MARKS;
+ pos ligature f_l
+ <anchor 300 800> mark @TOP_MARKS
+ <anchor 300 -200> mark @BOTTOM_MARKS
+ ligComponent
+ <anchor 600 800> mark @TOP_MARKS
+ <anchor 600 -200> mark @BOTTOM_MARKS;
- pos ligature [f_f_l] <anchor 300 800> mark @TOP_MARKS <anchor 300 -200> mark @BOTTOM_MARKS
- ligComponent <anchor 600 800> mark @TOP_MARKS <anchor 600 -200> mark @BOTTOM_MARKS
- ligComponent <anchor 900 800> mark @TOP_MARKS <anchor 900 -200> mark @BOTTOM_MARKS;
+ pos ligature [f_f_l]
+ <anchor 300 800> mark @TOP_MARKS
+ <anchor 300 -200> mark @BOTTOM_MARKS
+ ligComponent
+ <anchor 600 800> mark @TOP_MARKS
+ <anchor 600 -200> mark @BOTTOM_MARKS
+ ligComponent
+ <anchor 900 800> mark @TOP_MARKS
+ <anchor 900 -200> mark @BOTTOM_MARKS;
} test;
diff --git a/Tests/feaLib/data/GPOS_6.fea b/Tests/feaLib/data/GPOS_6.fea
index 37b29365..e54ff6e3 100644
--- a/Tests/feaLib/data/GPOS_6.fea
+++ b/Tests/feaLib/data/GPOS_6.fea
@@ -5,6 +5,9 @@ markClass macron <anchor 2 2 contourpoint 22> @TOP_MARKS;
markClass [cedilla] <anchor 3 3 contourpoint 33> @BOTTOM_MARKS;
feature test {
- pos mark [acute grave macron ogonek] <anchor 500 200> mark @TOP_MARKS <anchor 500 -80> mark @BOTTOM_MARKS;
- pos mark [dieresis caron] <anchor 500 200> mark @TOP_MARKS;
+ pos mark [acute grave macron ogonek]
+ <anchor 500 200> mark @TOP_MARKS
+ <anchor 500 -80> mark @BOTTOM_MARKS;
+ pos mark [dieresis caron]
+ <anchor 500 200> mark @TOP_MARKS;
} test;
diff --git a/Tests/feaLib/data/PairPosSubtable.ttx b/Tests/feaLib/data/PairPosSubtable.ttx
index 4b76f991..2d78f64f 100644
--- a/Tests/feaLib/data/PairPosSubtable.ttx
+++ b/Tests/feaLib/data/PairPosSubtable.ttx
@@ -76,6 +76,7 @@
<!-- Class2Count=2 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="-12"/>
@@ -105,8 +106,10 @@
<!-- Class2Count=3 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="2">
<Value1 XAdvance="-20"/>
@@ -114,11 +117,13 @@
</Class1Record>
<Class1Record index="1">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="-10"/>
</Class2Record>
<Class2Record index="2">
+ <Value1 XAdvance="0"/>
</Class2Record>
</Class1Record>
</PairPos>
diff --git a/Tests/feaLib/data/STAT_bad.fea b/Tests/feaLib/data/STAT_bad.fea
new file mode 100644
index 00000000..8ec887f0
--- /dev/null
+++ b/Tests/feaLib/data/STAT_bad.fea
@@ -0,0 +1,96 @@
+# bad fea file: Testing DesignAxis tag with incorrect label
+table name {
+ nameid 25 "TestFont";
+} name;
+
+
+table STAT {
+
+ ElidedFallbackName { name "Roman"; };
+
+ DesignAxis opsz 0 { badtag "Optical Size"; }; #'badtag' instead of 'name' is incorrect
+ DesignAxis wdth 1 { name "Width"; };
+ DesignAxis wght 2 { name "Weight"; };
+ DesignAxis ital 3 { name "Italic"; };
+
+ AxisValue {
+ location opsz 8 5 9;
+ location wdth 300 350 450;
+ name "Caption";
+ };
+
+ AxisValue {
+ location opsz 11 9 12;
+ name "Text";
+ flag OlderSiblingFontAttribute ElidableAxisValueName ;
+ };
+
+ AxisValue {
+ location opsz 16.7 12 24;
+ name "Subhead";
+ };
+
+ AxisValue {
+ location opsz 72 24 72;
+ name "Display";
+ };
+
+ AxisValue {
+ location wdth 80 80 89;
+ name "Condensed";
+ };
+
+ AxisValue {
+ location wdth 90 90 96;
+ name "Semicondensed";
+ };
+
+ AxisValue {
+ location wdth 100 97 101;
+ name "Normal";
+ flag ElidableAxisValueName;
+ };
+
+ AxisValue {
+ location wdth 125 102 125;
+ name "Extended";
+ };
+
+ AxisValue {
+ location wght 300 300 349;
+ name "Light";
+ };
+
+ AxisValue {
+ location wght 400 350 449;
+ name "Regular";
+ flag ElidableAxisValueName;
+ };
+
+ AxisValue {
+ location wght 500 450 549;
+ name "Medium";
+ };
+
+ AxisValue {
+ location wght 600 550 649;
+ name "Semibold";
+ };
+
+ AxisValue {
+ location wght 700 650 749;
+ name "Bold";
+ };
+
+ AxisValue {
+ location wght 900 750 900;
+ name "Black";
+ };
+
+ AxisValue {
+ location ital 0;
+ name "Roman";
+ flag ElidableAxisValueName;
+ };
+
+} STAT;
diff --git a/Tests/feaLib/data/STAT_test.fea b/Tests/feaLib/data/STAT_test.fea
new file mode 100644
index 00000000..01036376
--- /dev/null
+++ b/Tests/feaLib/data/STAT_test.fea
@@ -0,0 +1,109 @@
+table name {
+ nameid 25 "TestFont";
+} name;
+
+
+table STAT {
+
+ ElidedFallbackName {
+ name "Roman";
+ name 3 1 1041 "ローマン";
+ };
+
+ DesignAxis opsz 0 {
+ name "Optical Size";
+ };
+
+ DesignAxis wdth 1 {
+ name "Width";
+ };
+
+ DesignAxis wght 2 {
+ name "Weight";
+ };
+
+ DesignAxis ital 3 {
+ name "Italic";
+ }; # here comment
+
+ AxisValue {
+ location opsz 8; # comment here
+ location wdth 400; # another comment
+ name "Caption"; # more comments
+ };
+
+ AxisValue {
+ location opsz 11 9 12;
+ name "Text";
+ flag OlderSiblingFontAttribute ElidableAxisValueName;
+ };
+
+ AxisValue {
+ location opsz 16.7 12 24;
+ name "Subhead";
+ };
+
+ AxisValue {
+ location opsz 72 24 72;
+ name "Display";
+ };
+
+ AxisValue {
+ location wdth 80 80 89;
+ name "Condensed";
+ };
+
+ AxisValue {
+ location wdth 90 90 96;
+ name "Semicondensed";
+ };
+
+ AxisValue {
+ location wdth 100 97 101;
+ name "Normal";
+ flag ElidableAxisValueName;
+ };
+
+ AxisValue {
+ location wdth 125 102 125;
+ name "Extended";
+ };
+
+ AxisValue {
+ location wght 300 300 349;
+ name "Light";
+ };
+
+ AxisValue {
+ location wght 400 350 449;
+ name "Regular";
+ flag ElidableAxisValueName;
+ };
+
+ AxisValue {
+ location wght 500 450 549;
+ name "Medium";
+ };
+
+ AxisValue {
+ location wght 600 550 649;
+ name "Semibold";
+ };
+
+ AxisValue {
+ location wght 700 650 749;
+ name "Bold";
+ };
+
+ AxisValue {
+ location wght 900 750 900;
+ name "Black";
+ };
+
+ AxisValue {
+ location ital 0;
+ name "Roman";
+ flag ElidableAxisValueName; # flag comment
+ };
+
+} STAT;
diff --git a/Tests/feaLib/data/STAT_test.ttx b/Tests/feaLib/data/STAT_test.ttx
new file mode 100644
index 00000000..d1b2b697
--- /dev/null
+++ b/Tests/feaLib/data/STAT_test.ttx
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
+
+ <name>
+ <namerecord nameID="25" platformID="3" platEncID="1" langID="0x409">
+ TestFont
+ </namerecord>
+ <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
+ Roman
+ </namerecord>
+ <namerecord nameID="256" platformID="3" platEncID="1" langID="0x411">
+ ローマン
+ </namerecord>
+ <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
+ Optical Size
+ </namerecord>
+ <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
+ Text
+ </namerecord>
+ <namerecord nameID="259" platformID="3" platEncID="1" langID="0x409">
+ Subhead
+ </namerecord>
+ <namerecord nameID="260" platformID="3" platEncID="1" langID="0x409">
+ Display
+ </namerecord>
+ <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
+ Width
+ </namerecord>
+ <namerecord nameID="262" platformID="3" platEncID="1" langID="0x409">
+ Condensed
+ </namerecord>
+ <namerecord nameID="263" platformID="3" platEncID="1" langID="0x409">
+ Semicondensed
+ </namerecord>
+ <namerecord nameID="264" platformID="3" platEncID="1" langID="0x409">
+ Normal
+ </namerecord>
+ <namerecord nameID="265" platformID="3" platEncID="1" langID="0x409">
+ Extended
+ </namerecord>
+ <namerecord nameID="266" platformID="3" platEncID="1" langID="0x409">
+ Weight
+ </namerecord>
+ <namerecord nameID="267" platformID="3" platEncID="1" langID="0x409">
+ Light
+ </namerecord>
+ <namerecord nameID="268" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="269" platformID="3" platEncID="1" langID="0x409">
+ Medium
+ </namerecord>
+ <namerecord nameID="270" platformID="3" platEncID="1" langID="0x409">
+ Semibold
+ </namerecord>
+ <namerecord nameID="271" platformID="3" platEncID="1" langID="0x409">
+ Bold
+ </namerecord>
+ <namerecord nameID="272" platformID="3" platEncID="1" langID="0x409">
+ Black
+ </namerecord>
+ <namerecord nameID="273" platformID="3" platEncID="1" langID="0x409">
+ Italic
+ </namerecord>
+ <namerecord nameID="274" platformID="3" platEncID="1" langID="0x409">
+ Roman
+ </namerecord>
+ <namerecord nameID="275" platformID="3" platEncID="1" langID="0x409">
+ Caption
+ </namerecord>
+ </name>
+
+ <STAT>
+ <Version value="0x00010002"/>
+ <DesignAxisRecordSize value="8"/>
+ <!-- DesignAxisCount=4 -->
+ <DesignAxisRecord>
+ <Axis index="0">
+ <AxisTag value="opsz"/>
+ <AxisNameID value="257"/> <!-- Optical Size -->
+ <AxisOrdering value="0"/>
+ </Axis>
+ <Axis index="1">
+ <AxisTag value="wdth"/>
+ <AxisNameID value="261"/> <!-- Width -->
+ <AxisOrdering value="1"/>
+ </Axis>
+ <Axis index="2">
+ <AxisTag value="wght"/>
+ <AxisNameID value="266"/> <!-- Weight -->
+ <AxisOrdering value="2"/>
+ </Axis>
+ <Axis index="3">
+ <AxisTag value="ital"/>
+ <AxisNameID value="273"/> <!-- Italic -->
+ <AxisOrdering value="3"/>
+ </Axis>
+ </DesignAxisRecord>
+ <!-- AxisValueCount=15 -->
+ <AxisValueArray>
+ <AxisValue index="0" Format="4">
+ <!-- AxisCount=2 -->
+ <Flags value="0"/>
+ <ValueNameID value="275"/> <!-- Caption -->
+ <AxisValueRecord index="0">
+ <AxisIndex value="0"/>
+ <Value value="8.0"/>
+ </AxisValueRecord>
+ <AxisValueRecord index="1">
+ <AxisIndex value="1"/>
+ <Value value="400.0"/>
+ </AxisValueRecord>
+ </AxisValue>
+ <AxisValue index="1" Format="2">
+ <AxisIndex value="0"/>
+ <Flags value="3"/> <!-- OlderSiblingFontAttribute ElidableAxisValueName -->
+ <ValueNameID value="258"/> <!-- Text -->
+ <NominalValue value="11.0"/>
+ <RangeMinValue value="9.0"/>
+ <RangeMaxValue value="12.0"/>
+ </AxisValue>
+ <AxisValue index="2" Format="2">
+ <AxisIndex value="0"/>
+ <Flags value="0"/>
+ <ValueNameID value="259"/> <!-- Subhead -->
+ <NominalValue value="16.7"/>
+ <RangeMinValue value="12.0"/>
+ <RangeMaxValue value="24.0"/>
+ </AxisValue>
+ <AxisValue index="3" Format="2">
+ <AxisIndex value="0"/>
+ <Flags value="0"/>
+ <ValueNameID value="260"/> <!-- Display -->
+ <NominalValue value="72.0"/>
+ <RangeMinValue value="24.0"/>
+ <RangeMaxValue value="72.0"/>
+ </AxisValue>
+ <AxisValue index="4" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="0"/>
+ <ValueNameID value="262"/> <!-- Condensed -->
+ <NominalValue value="80.0"/>
+ <RangeMinValue value="80.0"/>
+ <RangeMaxValue value="89.0"/>
+ </AxisValue>
+ <AxisValue index="5" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="0"/>
+ <ValueNameID value="263"/> <!-- Semicondensed -->
+ <NominalValue value="90.0"/>
+ <RangeMinValue value="90.0"/>
+ <RangeMaxValue value="96.0"/>
+ </AxisValue>
+ <AxisValue index="6" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="2"/> <!-- ElidableAxisValueName -->
+ <ValueNameID value="264"/> <!-- Normal -->
+ <NominalValue value="100.0"/>
+ <RangeMinValue value="97.0"/>
+ <RangeMaxValue value="101.0"/>
+ </AxisValue>
+ <AxisValue index="7" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="0"/>
+ <ValueNameID value="265"/> <!-- Extended -->
+ <NominalValue value="125.0"/>
+ <RangeMinValue value="102.0"/>
+ <RangeMaxValue value="125.0"/>
+ </AxisValue>
+ <AxisValue index="8" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="267"/> <!-- Light -->
+ <NominalValue value="300.0"/>
+ <RangeMinValue value="300.0"/>
+ <RangeMaxValue value="349.0"/>
+ </AxisValue>
+ <AxisValue index="9" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="2"/> <!-- ElidableAxisValueName -->
+ <ValueNameID value="268"/> <!-- Regular -->
+ <NominalValue value="400.0"/>
+ <RangeMinValue value="350.0"/>
+ <RangeMaxValue value="449.0"/>
+ </AxisValue>
+ <AxisValue index="10" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="269"/> <!-- Medium -->
+ <NominalValue value="500.0"/>
+ <RangeMinValue value="450.0"/>
+ <RangeMaxValue value="549.0"/>
+ </AxisValue>
+ <AxisValue index="11" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="270"/> <!-- Semibold -->
+ <NominalValue value="600.0"/>
+ <RangeMinValue value="550.0"/>
+ <RangeMaxValue value="649.0"/>
+ </AxisValue>
+ <AxisValue index="12" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="271"/> <!-- Bold -->
+ <NominalValue value="700.0"/>
+ <RangeMinValue value="650.0"/>
+ <RangeMaxValue value="749.0"/>
+ </AxisValue>
+ <AxisValue index="13" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="272"/> <!-- Black -->
+ <NominalValue value="900.0"/>
+ <RangeMinValue value="750.0"/>
+ <RangeMaxValue value="900.0"/>
+ </AxisValue>
+ <AxisValue index="14" Format="1">
+ <AxisIndex value="3"/>
+ <Flags value="2"/> <!-- ElidableAxisValueName -->
+ <ValueNameID value="274"/> <!-- Roman -->
+ <Value value="0.0"/>
+ </AxisValue>
+ </AxisValueArray>
+ <ElidedFallbackNameID value="256"/> <!-- Roman -->
+ </STAT>
+
+</ttFont>
diff --git a/Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea b/Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea
new file mode 100644
index 00000000..5a141803
--- /dev/null
+++ b/Tests/feaLib/data/STAT_test_elidedFallbackNameID.fea
@@ -0,0 +1,84 @@
+table name {
+ nameid 25 "TestFont";
+ nameid 256 "Roman";
+} name;
+table STAT {
+ ElidedFallbackNameID 256;
+ DesignAxis opsz 0 {
+ name "Optical Size";
+ };
+ DesignAxis wdth 1 {
+ name "Width";
+ };
+ DesignAxis wght 2 {
+ name "Weight";
+ };
+ DesignAxis ital 3 {
+ name "Italic";
+ }; # here comment
+ AxisValue {
+ location opsz 8; # comment here
+ location wdth 400; # another comment
+ name "Caption"; # more comments
+ };
+ AxisValue {
+ location opsz 11 9 12;
+ name "Text";
+ flag OlderSiblingFontAttribute ElidableAxisValueName;
+ };
+ AxisValue {
+ location opsz 16.7 12 24;
+ name "Subhead";
+ };
+ AxisValue {
+ location opsz 72 24 72;
+ name "Display";
+ };
+ AxisValue {
+ location wdth 80 80 89;
+ name "Condensed";
+ };
+ AxisValue {
+ location wdth 90 90 96;
+ name "Semicondensed";
+ };
+ AxisValue {
+ location wdth 100 97 101;
+ name "Normal";
+ flag ElidableAxisValueName;
+ };
+ AxisValue {
+ location wdth 125 102 125;
+ name "Extended";
+ };
+ AxisValue {
+ location wght 300 300 349;
+ name "Light";
+ };
+ AxisValue {
+ location wght 400 350 449;
+ name "Regular";
+ flag ElidableAxisValueName;
+ };
+ AxisValue {
+ location wght 500 450 549;
+ name "Medium";
+ };
+ AxisValue {
+ location wght 600 550 649;
+ name "Semibold";
+ };
+ AxisValue {
+ location wght 700 650 749;
+ name "Bold";
+ };
+ AxisValue {
+ location wght 900 750 900;
+ name "Black";
+ };
+ AxisValue {
+ location ital 0;
+ name "Roman";
+ flag ElidableAxisValueName; # flag comment
+ };
+} STAT; \ No newline at end of file
diff --git a/Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx b/Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx
new file mode 100644
index 00000000..32802e0f
--- /dev/null
+++ b/Tests/feaLib/data/STAT_test_elidedFallbackNameID.ttx
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.20">
+
+ <name>
+ <namerecord nameID="25" platformID="3" platEncID="1" langID="0x409">
+ TestFont
+ </namerecord>
+ <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
+ Roman
+ </namerecord>
+ <namerecord nameID="257" platformID="3" platEncID="1" langID="0x409">
+ Optical Size
+ </namerecord>
+ <namerecord nameID="258" platformID="3" platEncID="1" langID="0x409">
+ Text
+ </namerecord>
+ <namerecord nameID="259" platformID="3" platEncID="1" langID="0x409">
+ Subhead
+ </namerecord>
+ <namerecord nameID="260" platformID="3" platEncID="1" langID="0x409">
+ Display
+ </namerecord>
+ <namerecord nameID="261" platformID="3" platEncID="1" langID="0x409">
+ Width
+ </namerecord>
+ <namerecord nameID="262" platformID="3" platEncID="1" langID="0x409">
+ Condensed
+ </namerecord>
+ <namerecord nameID="263" platformID="3" platEncID="1" langID="0x409">
+ Semicondensed
+ </namerecord>
+ <namerecord nameID="264" platformID="3" platEncID="1" langID="0x409">
+ Normal
+ </namerecord>
+ <namerecord nameID="265" platformID="3" platEncID="1" langID="0x409">
+ Extended
+ </namerecord>
+ <namerecord nameID="266" platformID="3" platEncID="1" langID="0x409">
+ Weight
+ </namerecord>
+ <namerecord nameID="267" platformID="3" platEncID="1" langID="0x409">
+ Light
+ </namerecord>
+ <namerecord nameID="268" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="269" platformID="3" platEncID="1" langID="0x409">
+ Medium
+ </namerecord>
+ <namerecord nameID="270" platformID="3" platEncID="1" langID="0x409">
+ Semibold
+ </namerecord>
+ <namerecord nameID="271" platformID="3" platEncID="1" langID="0x409">
+ Bold
+ </namerecord>
+ <namerecord nameID="272" platformID="3" platEncID="1" langID="0x409">
+ Black
+ </namerecord>
+ <namerecord nameID="273" platformID="3" platEncID="1" langID="0x409">
+ Italic
+ </namerecord>
+ <namerecord nameID="274" platformID="3" platEncID="1" langID="0x409">
+ Roman
+ </namerecord>
+ <namerecord nameID="275" platformID="3" platEncID="1" langID="0x409">
+ Caption
+ </namerecord>
+ </name>
+
+ <STAT>
+ <Version value="0x00010002"/>
+ <DesignAxisRecordSize value="8"/>
+ <!-- DesignAxisCount=4 -->
+ <DesignAxisRecord>
+ <Axis index="0">
+ <AxisTag value="opsz"/>
+ <AxisNameID value="257"/> <!-- Optical Size -->
+ <AxisOrdering value="0"/>
+ </Axis>
+ <Axis index="1">
+ <AxisTag value="wdth"/>
+ <AxisNameID value="261"/> <!-- Width -->
+ <AxisOrdering value="1"/>
+ </Axis>
+ <Axis index="2">
+ <AxisTag value="wght"/>
+ <AxisNameID value="266"/> <!-- Weight -->
+ <AxisOrdering value="2"/>
+ </Axis>
+ <Axis index="3">
+ <AxisTag value="ital"/>
+ <AxisNameID value="273"/> <!-- Italic -->
+ <AxisOrdering value="3"/>
+ </Axis>
+ </DesignAxisRecord>
+ <!-- AxisValueCount=15 -->
+ <AxisValueArray>
+ <AxisValue index="0" Format="4">
+ <!-- AxisCount=2 -->
+ <Flags value="0"/>
+ <ValueNameID value="275"/> <!-- Caption -->
+ <AxisValueRecord index="0">
+ <AxisIndex value="0"/>
+ <Value value="8.0"/>
+ </AxisValueRecord>
+ <AxisValueRecord index="1">
+ <AxisIndex value="1"/>
+ <Value value="400.0"/>
+ </AxisValueRecord>
+ </AxisValue>
+ <AxisValue index="1" Format="2">
+ <AxisIndex value="0"/>
+ <Flags value="3"/> <!-- OlderSiblingFontAttribute ElidableAxisValueName -->
+ <ValueNameID value="258"/> <!-- Text -->
+ <NominalValue value="11.0"/>
+ <RangeMinValue value="9.0"/>
+ <RangeMaxValue value="12.0"/>
+ </AxisValue>
+ <AxisValue index="2" Format="2">
+ <AxisIndex value="0"/>
+ <Flags value="0"/>
+ <ValueNameID value="259"/> <!-- Subhead -->
+ <NominalValue value="16.7"/>
+ <RangeMinValue value="12.0"/>
+ <RangeMaxValue value="24.0"/>
+ </AxisValue>
+ <AxisValue index="3" Format="2">
+ <AxisIndex value="0"/>
+ <Flags value="0"/>
+ <ValueNameID value="260"/> <!-- Display -->
+ <NominalValue value="72.0"/>
+ <RangeMinValue value="24.0"/>
+ <RangeMaxValue value="72.0"/>
+ </AxisValue>
+ <AxisValue index="4" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="0"/>
+ <ValueNameID value="262"/> <!-- Condensed -->
+ <NominalValue value="80.0"/>
+ <RangeMinValue value="80.0"/>
+ <RangeMaxValue value="89.0"/>
+ </AxisValue>
+ <AxisValue index="5" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="0"/>
+ <ValueNameID value="263"/> <!-- Semicondensed -->
+ <NominalValue value="90.0"/>
+ <RangeMinValue value="90.0"/>
+ <RangeMaxValue value="96.0"/>
+ </AxisValue>
+ <AxisValue index="6" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="2"/> <!-- ElidableAxisValueName -->
+ <ValueNameID value="264"/> <!-- Normal -->
+ <NominalValue value="100.0"/>
+ <RangeMinValue value="97.0"/>
+ <RangeMaxValue value="101.0"/>
+ </AxisValue>
+ <AxisValue index="7" Format="2">
+ <AxisIndex value="1"/>
+ <Flags value="0"/>
+ <ValueNameID value="265"/> <!-- Extended -->
+ <NominalValue value="125.0"/>
+ <RangeMinValue value="102.0"/>
+ <RangeMaxValue value="125.0"/>
+ </AxisValue>
+ <AxisValue index="8" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="267"/> <!-- Light -->
+ <NominalValue value="300.0"/>
+ <RangeMinValue value="300.0"/>
+ <RangeMaxValue value="349.0"/>
+ </AxisValue>
+ <AxisValue index="9" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="2"/> <!-- ElidableAxisValueName -->
+ <ValueNameID value="268"/> <!-- Regular -->
+ <NominalValue value="400.0"/>
+ <RangeMinValue value="350.0"/>
+ <RangeMaxValue value="449.0"/>
+ </AxisValue>
+ <AxisValue index="10" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="269"/> <!-- Medium -->
+ <NominalValue value="500.0"/>
+ <RangeMinValue value="450.0"/>
+ <RangeMaxValue value="549.0"/>
+ </AxisValue>
+ <AxisValue index="11" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="270"/> <!-- Semibold -->
+ <NominalValue value="600.0"/>
+ <RangeMinValue value="550.0"/>
+ <RangeMaxValue value="649.0"/>
+ </AxisValue>
+ <AxisValue index="12" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="271"/> <!-- Bold -->
+ <NominalValue value="700.0"/>
+ <RangeMinValue value="650.0"/>
+ <RangeMaxValue value="749.0"/>
+ </AxisValue>
+ <AxisValue index="13" Format="2">
+ <AxisIndex value="2"/>
+ <Flags value="0"/>
+ <ValueNameID value="272"/> <!-- Black -->
+ <NominalValue value="900.0"/>
+ <RangeMinValue value="750.0"/>
+ <RangeMaxValue value="900.0"/>
+ </AxisValue>
+ <AxisValue index="14" Format="1">
+ <AxisIndex value="3"/>
+ <Flags value="2"/> <!-- ElidableAxisValueName -->
+ <ValueNameID value="274"/> <!-- Roman -->
+ <Value value="0.0"/>
+ </AxisValue>
+ </AxisValueArray>
+ <ElidedFallbackNameID value="256"/> <!-- Roman -->
+ </STAT>
+
+</ttFont>
diff --git a/Tests/feaLib/data/bug453.fea b/Tests/feaLib/data/bug453.fea
index 486632ee..ed0e6f94 100644
--- a/Tests/feaLib/data/bug453.fea
+++ b/Tests/feaLib/data/bug453.fea
@@ -2,10 +2,12 @@
feature mark {
lookup mark1 {
markClass [acute] <anchor 150 -10> @TOP_MARKS;
- pos base [e] <anchor 250 450> mark @TOP_MARKS;
+ pos base [e]
+ <anchor 250 450> mark @TOP_MARKS;
} mark1;
lookup mark2 {
markClass [acute] <anchor 150 -20> @TOP_MARKS_2;
- pos base [e] <anchor 250 450> mark @TOP_MARKS_2;
+ pos base [e]
+ <anchor 250 450> mark @TOP_MARKS_2;
} mark2;
} mark;
diff --git a/Tests/feaLib/data/bug633.ttx b/Tests/feaLib/data/bug633.ttx
index b119ebbe..075c1777 100644
--- a/Tests/feaLib/data/bug633.ttx
+++ b/Tests/feaLib/data/bug633.ttx
@@ -52,6 +52,7 @@
<!-- Class2Count=3 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="0"/>
diff --git a/Tests/feaLib/data/size2.ttx b/Tests/feaLib/data/size2.ttx
index a822af36..1a12ddfc 100644
--- a/Tests/feaLib/data/size2.ttx
+++ b/Tests/feaLib/data/size2.ttx
@@ -26,8 +26,8 @@
<DesignSize value="10.0"/>
<SubfamilyID value="0"/>
<SubfamilyNameID value="0"/>
- <RangeStart value="0"/>
- <RangeEnd value="0"/>
+ <RangeStart value="0.0"/>
+ <RangeEnd value="0.0"/>
</FeatureParamsSize>
<!-- LookupCount=0 -->
</Feature>
diff --git a/Tests/feaLib/data/spec6b_ii.ttx b/Tests/feaLib/data/spec6b_ii.ttx
index a7131ded..c7b8de81 100644
--- a/Tests/feaLib/data/spec6b_ii.ttx
+++ b/Tests/feaLib/data/spec6b_ii.ttx
@@ -91,6 +91,7 @@
<!-- Class2Count=2 -->
<Class1Record index="0">
<Class2Record index="0">
+ <Value1 XAdvance="0"/>
</Class2Record>
<Class2Record index="1">
<Value1 XAdvance="-100"/>
diff --git a/Tests/feaLib/data/spec6d2.fea b/Tests/feaLib/data/spec6d2.fea
index ead224fe..5c2620d2 100644
--- a/Tests/feaLib/data/spec6d2.fea
+++ b/Tests/feaLib/data/spec6d2.fea
@@ -9,7 +9,11 @@ markClass [dieresis umlaut] <anchor 300 -10> @TOP_MARKS;
markClass [cedilla] <anchor 300 600> @BOTTOM_MARKS;
feature test {
- pos base [e o] <anchor 250 450> mark @TOP_MARKS <anchor 250 -12> mark @BOTTOM_MARKS;
-#test-fea2fea: pos base [a u] <anchor 265 450> mark @TOP_MARKS <anchor 250 -10> mark @BOTTOM_MARKS;
- position base [a u] <anchor 265 450> mark @TOP_MARKS <anchor 250-10> mark @BOTTOM_MARKS;
+ pos base [e o]
+ <anchor 250 450> mark @TOP_MARKS
+ <anchor 250 -12> mark @BOTTOM_MARKS;
+#test-fea2fea: pos base [a u]
+ position base [a u]
+ <anchor 265 450> mark @TOP_MARKS
+ <anchor 250 -10> mark @BOTTOM_MARKS;
} test;
diff --git a/Tests/feaLib/data/spec6e.fea b/Tests/feaLib/data/spec6e.fea
index ed956c8f..64612232 100644
--- a/Tests/feaLib/data/spec6e.fea
+++ b/Tests/feaLib/data/spec6e.fea
@@ -4,7 +4,10 @@ markClass sukun <anchor 261 488> @TOP_MARKS;
markClass kasratan <anchor 346 -98> @BOTTOM_MARKS;
feature test {
- pos ligature lam_meem_jeem <anchor 625 1800> mark @TOP_MARKS # mark above lam
- ligComponent <anchor 376 -368> mark @BOTTOM_MARKS # mark below meem
- ligComponent <anchor NULL>; # jeem has no marks
+ pos ligature lam_meem_jeem
+ <anchor 625 1800> mark @TOP_MARKS # mark above lam
+ ligComponent
+ <anchor 376 -368> mark @BOTTOM_MARKS # mark below meem
+ ligComponent
+ <anchor NULL>; # jeem has no marks
} test;
diff --git a/Tests/feaLib/data/spec6f.fea b/Tests/feaLib/data/spec6f.fea
index 8d32008c..277bdb46 100644
--- a/Tests/feaLib/data/spec6f.fea
+++ b/Tests/feaLib/data/spec6f.fea
@@ -2,5 +2,6 @@ languagesystem DFLT dflt;
feature test {
markClass damma <anchor 189 -103> @MARK_CLASS_1;
- pos mark hamza <anchor 221 301> mark @MARK_CLASS_1;
+ pos mark hamza
+ <anchor 221 301> mark @MARK_CLASS_1;
} test;
diff --git a/Tests/feaLib/data/spec6h_ii.fea b/Tests/feaLib/data/spec6h_ii.fea
index 36a1f032..690d2a35 100644
--- a/Tests/feaLib/data/spec6h_ii.fea
+++ b/Tests/feaLib/data/spec6h_ii.fea
@@ -12,8 +12,10 @@ lookup CNTXT_PAIR_POS {
} CNTXT_PAIR_POS;
lookup CNTXT_MARK_TO_BASE {
- pos base o <anchor 250 450> mark @ALL_MARKS;
- pos base c <anchor 250 450> mark @ALL_MARKS;
+ pos base o
+ <anchor 250 450> mark @ALL_MARKS;
+ pos base c
+ <anchor 250 450> mark @ALL_MARKS;
} CNTXT_MARK_TO_BASE;
feature test {
diff --git a/Tests/feaLib/lexer_test.py b/Tests/feaLib/lexer_test.py
index 238552ec..24dc5dba 100644
--- a/Tests/feaLib/lexer_test.py
+++ b/Tests/feaLib/lexer_test.py
@@ -1,6 +1,7 @@
-from fontTools.misc.py23 import *
+from fontTools.misc.py23 import tobytes
from fontTools.feaLib.error import FeatureLibError, IncludedFeaNotFound
from fontTools.feaLib.lexer import IncludingLexer, Lexer
+from io import StringIO
import os
import shutil
import tempfile
@@ -184,7 +185,7 @@ class IncludingLexerTest(unittest.TestCase):
lambda: list(lexer))
def test_featurefilepath_None(self):
- lexer = IncludingLexer(UnicodeIO("# foobar"))
+ lexer = IncludingLexer(StringIO("# foobar"))
self.assertIsNone(lexer.featurefilepath)
files = set(loc.file for _, _, loc in lexer)
self.assertIn("<features>", files)
@@ -196,7 +197,7 @@ class IncludingLexerTest(unittest.TestCase):
pos A B -40;
} kern;
""", encoding="utf-8"))
- including = UnicodeIO("include(%s);" % included.name)
+ including = StringIO("include(%s);" % included.name)
try:
lexer = IncludingLexer(including)
files = set(loc.file for _, _, loc in lexer)
@@ -224,7 +225,7 @@ class IncludingLexerTest(unittest.TestCase):
# itself have a path, because it was initialized from
# an in-memory stream, so it will use the current working
# directory to resolve relative include statements
- lexer = IncludingLexer(UnicodeIO("include(included.fea);"))
+ lexer = IncludingLexer(StringIO("include(included.fea);"))
files = set(os.path.realpath(loc.file) for _, _, loc in lexer)
expected = os.path.realpath(included.name)
self.assertIn(expected, files)
diff --git a/Tests/feaLib/parser_test.py b/Tests/feaLib/parser_test.py
index db505950..de2bc3ca 100644
--- a/Tests/feaLib/parser_test.py
+++ b/Tests/feaLib/parser_test.py
@@ -1280,6 +1280,76 @@ class ParserTest(unittest.TestCase):
'"dflt" is not a valid script tag; use "DFLT" instead',
self.parse, "feature test {script dflt;} test;")
+ def test_stat_design_axis(self): # STAT DesignAxis
+ doc = self.parse('table STAT { DesignAxis opsz 0 '
+ '{name "Optical Size";}; } STAT;')
+ da = doc.statements[0].statements[0]
+ self.assertIsInstance(da, ast.STATDesignAxisStatement)
+ self.assertEqual(da.tag, 'opsz')
+ self.assertEqual(da.axisOrder, 0)
+ self.assertEqual(da.names[0].string, 'Optical Size')
+
+ def test_stat_axis_value_format1(self): # STAT AxisValue
+ doc = self.parse('table STAT { DesignAxis opsz 0 '
+ '{name "Optical Size";}; '
+ 'AxisValue {location opsz 8; name "Caption";}; } '
+ 'STAT;')
+ avr = doc.statements[0].statements[1]
+ self.assertIsInstance(avr, ast.STATAxisValueStatement)
+ self.assertEqual(avr.locations[0].tag, 'opsz')
+ self.assertEqual(avr.locations[0].values[0], 8)
+ self.assertEqual(avr.names[0].string, 'Caption')
+
+ def test_stat_axis_value_format2(self): # STAT AxisValue
+ doc = self.parse('table STAT { DesignAxis opsz 0 '
+ '{name "Optical Size";}; '
+ 'AxisValue {location opsz 8 6 10; name "Caption";}; } '
+ 'STAT;')
+ avr = doc.statements[0].statements[1]
+ self.assertIsInstance(avr, ast.STATAxisValueStatement)
+ self.assertEqual(avr.locations[0].tag, 'opsz')
+ self.assertEqual(avr.locations[0].values, [8, 6, 10])
+ self.assertEqual(avr.names[0].string, 'Caption')
+
+ def test_stat_axis_value_format2_bad_range(self): # STAT AxisValue
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'Default value 5 is outside of specified range 6-10.',
+ self.parse, 'table STAT { DesignAxis opsz 0 '
+ '{name "Optical Size";}; '
+ 'AxisValue {location opsz 5 6 10; name "Caption";}; } '
+ 'STAT;')
+
+ def test_stat_axis_value_format4(self): # STAT AxisValue
+ self.assertRaisesRegex(
+ FeatureLibError,
+ 'Only one value is allowed in a Format 4 Axis Value Record, but 3 were found.',
+ self.parse, 'table STAT { '
+ 'DesignAxis opsz 0 {name "Optical Size";}; '
+ 'DesignAxis wdth 0 {name "Width";}; '
+ 'AxisValue {'
+ 'location opsz 8 6 10; '
+ 'location wdth 400; '
+ 'name "Caption";}; } '
+ 'STAT;')
+
+ def test_stat_elidedfallbackname(self): # STAT ElidedFallbackName
+ doc = self.parse('table STAT { ElidedFallbackName {name "Roman"; '
+ 'name 3 1 0x0411 "ローマン"; }; '
+ '} STAT;')
+ nameRecord = doc.statements[0].statements[0]
+ self.assertIsInstance(nameRecord, ast.ElidedFallbackName)
+ self.assertEqual(nameRecord.names[0].string, 'Roman')
+ self.assertEqual(nameRecord.names[1].string, 'ローマン')
+
+ def test_stat_elidedfallbacknameid(self): # STAT ElidedFallbackNameID
+ doc = self.parse('table name { nameid 278 "Roman"; } name; '
+ 'table STAT { ElidedFallbackNameID 278; '
+ '} STAT;')
+ nameRecord = doc.statements[0].statements[0]
+ self.assertIsInstance(nameRecord, ast.NameRecord)
+ self.assertEqual(nameRecord.string, 'Roman')
+
def test_sub_single_format_a(self): # GSUB LookupType 1
doc = self.parse("feature smcp {substitute a by a.sc;} smcp;")
sub = doc.statements[0].statements[0]