diff options
Diffstat (limited to 'Tests/voltLib/parser_test.py')
-rw-r--r-- | Tests/voltLib/parser_test.py | 345 |
1 files changed, 228 insertions, 117 deletions
diff --git a/Tests/voltLib/parser_test.py b/Tests/voltLib/parser_test.py index 3bfa17c8..0e0191fc 100644 --- a/Tests/voltLib/parser_test.py +++ b/Tests/voltLib/parser_test.py @@ -1,9 +1,7 @@ -from __future__ import print_function, division, absolute_import -from __future__ import unicode_literals -from fontTools.misc.py23 import * from fontTools.voltLib import ast from fontTools.voltLib.error import VoltLibError from fontTools.voltLib.parser import Parser +from io import StringIO import unittest @@ -39,7 +37,7 @@ class ParserTest(unittest.TestCase): ("space", 3, [0x0020], "BASE", None)) def test_def_glyph_base_with_unicodevalues(self): - [def_glyph] = self.parse( + [def_glyph] = self.parse_( 'DEF_GLYPH "CR" ID 2 UNICODEVALUES "U+0009" ' 'TYPE BASE END_GLYPH' ).statements @@ -57,7 +55,7 @@ class ParserTest(unittest.TestCase): ("CR", 2, [0x0009, 0x000D], "BASE", None)) def test_def_glyph_base_with_empty_unicodevalues(self): - [def_glyph] = self.parse( + [def_glyph] = self.parse_( 'DEF_GLYPH "i.locl" ID 269 UNICODEVALUES "" ' 'TYPE BASE END_GLYPH' ).statements @@ -108,7 +106,7 @@ class ParserTest(unittest.TestCase): def test_def_glyph_case_sensitive(self): def_glyphs = self.parse( 'DEF_GLYPH "A" ID 3 UNICODE 65 TYPE BASE END_GLYPH\n' - 'DEF_GLYPH "a" ID 4 UNICODE 97 TYPE BASE END_GLYPH\n' + 'DEF_GLYPH "a" ID 4 UNICODE 97 TYPE BASE END_GLYPH' ).statements self.assertEqual((def_glyphs[0].name, def_glyphs[0].id, def_glyphs[0].unicode, def_glyphs[0].type, @@ -122,10 +120,10 @@ class ParserTest(unittest.TestCase): def test_def_group_glyphs(self): [def_group] = self.parse( 'DEF_GROUP "aaccented"\n' - 'ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" ' + ' ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" ' 'GLYPH "adieresis" GLYPH "ae" GLYPH "agrave" GLYPH "amacron" ' 'GLYPH "aogonek" GLYPH "aring" GLYPH "atilde" END_ENUM\n' - 'END_GROUP\n' + 'END_GROUP' ).statements self.assertEqual((def_group.name, def_group.enum.glyphSet()), ("aaccented", @@ -136,14 +134,14 @@ class ParserTest(unittest.TestCase): def test_def_group_groups(self): [group1, group2, test_group] = self.parse( 'DEF_GROUP "Group1"\n' - 'ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n' + ' ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "Group2"\n' - 'ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n' + ' ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "TestGroup"\n' - 'ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n' - 'END_GROUP\n' + ' ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n' + 'END_GROUP' ).statements groups = [g.group for g in test_group.enum.enum] self.assertEqual((test_group.name, groups), @@ -153,20 +151,20 @@ class ParserTest(unittest.TestCase): [group1, test_group1, test_group2, test_group3, group2] = \ self.parse( 'DEF_GROUP "Group1"\n' - 'ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n' + ' ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "TestGroup1"\n' - 'ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n' + ' ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "TestGroup2"\n' - 'ENUM GROUP "Group2" END_ENUM\n' + ' ENUM GROUP "Group2" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "TestGroup3"\n' - 'ENUM GROUP "Group2" GROUP "Group1" END_ENUM\n' + ' ENUM GROUP "Group2" GROUP "Group1" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "Group2"\n' - 'ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n' - 'END_GROUP\n' + ' ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n' + 'END_GROUP' ).statements groups = [g.group for g in test_group1.enum.enum] self.assertEqual( @@ -197,12 +195,12 @@ class ParserTest(unittest.TestCase): def test_def_group_glyphs_and_group(self): [def_group1, def_group2] = self.parse( 'DEF_GROUP "aaccented"\n' - 'ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" ' + ' ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" ' 'GLYPH "adieresis" GLYPH "ae" GLYPH "agrave" GLYPH "amacron" ' 'GLYPH "aogonek" GLYPH "aring" GLYPH "atilde" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "KERN_lc_a_2ND"\n' - 'ENUM GLYPH "a" GROUP "aaccented" END_ENUM\n' + ' ENUM GLYPH "a" GROUP "aaccented" END_ENUM\n' 'END_GROUP' ).statements items = def_group2.enum.enum @@ -221,7 +219,7 @@ class ParserTest(unittest.TestCase): 'DEF_GLYPH "ccedilla" ID 210 UNICODE 231 TYPE BASE END_GLYPH\n' 'DEF_GLYPH "cdotaccent" ID 210 UNICODE 267 TYPE BASE END_GLYPH\n' 'DEF_GROUP "KERN_lc_a_2ND"\n' - 'ENUM RANGE "a" TO "atilde" GLYPH "b" RANGE "c" TO "cdotaccent" ' + ' ENUM RANGE "a" TO "atilde" GLYPH "b" RANGE "c" TO "cdotaccent" ' 'END_ENUM\n' 'END_GROUP' ).statements[-1] @@ -240,7 +238,7 @@ class ParserTest(unittest.TestCase): 'END_GROUP\n' 'DEF_GROUP "dupe"\n' 'ENUM GLYPH "x" END_ENUM\n' - 'END_GROUP\n' + 'END_GROUP' ) def test_group_duplicate_case_insensitive(self): @@ -253,12 +251,12 @@ class ParserTest(unittest.TestCase): 'END_GROUP\n' 'DEF_GROUP "Dupe"\n' 'ENUM GLYPH "x" END_ENUM\n' - 'END_GROUP\n' + 'END_GROUP' ) def test_script_without_langsys(self): [script] = self.parse( - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' 'END_SCRIPT' ).statements self.assertEqual((script.name, script.tag, script.langs), @@ -266,10 +264,10 @@ class ParserTest(unittest.TestCase): def test_langsys_normal(self): [def_script] = self.parse( - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' - 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' + 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n' 'END_LANGSYS\n' - 'DEF_LANGSYS NAME "Moldavian" TAG "MOL "\n' + 'DEF_LANGSYS NAME "Moldavian" TAG "MOL "\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements @@ -287,8 +285,8 @@ class ParserTest(unittest.TestCase): def test_langsys_no_script_name(self): [langsys] = self.parse( - 'DEF_SCRIPT TAG "latn"\n' - 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' + 'DEF_SCRIPT TAG "latn"\n\n' + 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements @@ -305,8 +303,8 @@ class ParserTest(unittest.TestCase): VoltLibError, r'.*Expected "TAG"'): [langsys] = self.parse( - 'DEF_SCRIPT NAME "Latin"\n' - 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' + 'DEF_SCRIPT NAME "Latin"\n\n' + 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements @@ -317,12 +315,12 @@ class ParserTest(unittest.TestCase): 'Script "DFLT" already defined, ' 'script tags are case insensitive'): [langsys1, langsys2] = self.parse( - 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n' - 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' + 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n\n' + 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n' 'END_LANGSYS\n' 'END_SCRIPT\n' - 'DEF_SCRIPT TAG "DFLT"\n' - 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' + 'DEF_SCRIPT TAG "DFLT"\n\n' + 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements @@ -338,21 +336,21 @@ class ParserTest(unittest.TestCase): 'END_LANGSYS\n' 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' 'END_LANGSYS\n' - 'END_SCRIPT\n' + 'END_SCRIPT' ).statements def test_langsys_lang_in_separate_scripts(self): [langsys1, langsys2] = self.parse( - 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n' - 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' + 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n\n' + 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n' 'END_LANGSYS\n' - 'DEF_LANGSYS NAME "Default" TAG "ROM "\n' + 'DEF_LANGSYS NAME "Default" TAG "ROM "\n\n' 'END_LANGSYS\n' 'END_SCRIPT\n' - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' - 'DEF_LANGSYS NAME "Default" TAG "dflt"\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' + 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n' 'END_LANGSYS\n' - 'DEF_LANGSYS NAME "Default" TAG "ROM "\n' + 'DEF_LANGSYS NAME "Default" TAG "ROM "\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements @@ -363,8 +361,8 @@ class ParserTest(unittest.TestCase): def test_langsys_no_lang_name(self): [langsys] = self.parse( - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' - 'DEF_LANGSYS TAG "dflt"\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' + 'DEF_LANGSYS TAG "dflt"\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements @@ -381,18 +379,18 @@ class ParserTest(unittest.TestCase): VoltLibError, r'.*Expected "TAG"'): [langsys] = self.parse( - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' - 'DEF_LANGSYS NAME "Default"\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' + 'DEF_LANGSYS NAME "Default"\n\n' 'END_LANGSYS\n' 'END_SCRIPT' ).statements def test_feature(self): [def_script] = self.parse( - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' - 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' + 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n' 'DEF_FEATURE NAME "Fractions" TAG "frac"\n' - 'LOOKUP "fraclookup"\n' + ' LOOKUP "fraclookup"\n' 'END_FEATURE\n' 'END_LANGSYS\n' 'END_SCRIPT' @@ -404,10 +402,10 @@ class ParserTest(unittest.TestCase): "frac", ["fraclookup"])) [def_script] = self.parse( - 'DEF_SCRIPT NAME "Latin" TAG "latn"\n' - 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n' + 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n' + 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n' 'DEF_FEATURE NAME "Kerning" TAG "kern"\n' - 'LOOKUP "kern1" LOOKUP "kern2"\n' + ' LOOKUP "kern1" LOOKUP "kern2"\n' 'END_FEATURE\n' 'END_LANGSYS\n' 'END_SCRIPT' @@ -475,6 +473,21 @@ class ParserTest(unittest.TestCase): 'END_SUBSTITUTION\n' ).statements + def test_lookup_comments(self): + [lookup] = self.parse( + 'DEF_LOOKUP "test" PROCESS_BASE PROCESS_MARKS ALL DIRECTION LTR\n' + 'COMMENTS "Hello\\nWorld"\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' + 'AS_SUBSTITUTION\n' + 'SUB GLYPH "a"\n' + 'WITH GLYPH "b"\n' + 'END_SUB\n' + 'END_SUBSTITUTION' + ).statements + self.assertEqual(lookup.name, "test") + self.assertEqual(lookup.comments, "Hello\nWorld") + def test_substitution_empty(self): with self.assertRaisesRegex( VoltLibError, @@ -559,12 +572,13 @@ class ParserTest(unittest.TestCase): def test_substitution_single_in_context(self): [group, lookup] = self.parse( - 'DEF_GROUP "Denominators" ENUM GLYPH "one.dnom" GLYPH "two.dnom" ' - 'END_ENUM END_GROUP\n' + 'DEF_GROUP "Denominators"\n' + ' ENUM GLYPH "one.dnom" GLYPH "two.dnom" END_ENUM\n' + 'END_GROUP\n' 'DEF_LOOKUP "fracdnom" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' - 'IN_CONTEXT LEFT ENUM GROUP "Denominators" GLYPH "fraction" ' - 'END_ENUM\n' + 'IN_CONTEXT\n' + ' LEFT ENUM GROUP "Denominators" GLYPH "fraction" END_ENUM\n' 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GLYPH "one"\n' @@ -590,17 +604,18 @@ class ParserTest(unittest.TestCase): def test_substitution_single_in_contexts(self): [group, lookup] = self.parse( - 'DEF_GROUP "Hebrew" ENUM GLYPH "uni05D0" GLYPH "uni05D1" ' - 'END_ENUM END_GROUP\n' + 'DEF_GROUP "Hebrew"\n' + ' ENUM GLYPH "uni05D0" GLYPH "uni05D1" END_ENUM\n' + 'END_GROUP\n' 'DEF_LOOKUP "HebrewCurrency" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' 'IN_CONTEXT\n' - 'RIGHT GROUP "Hebrew"\n' - 'RIGHT GLYPH "one.Hebr"\n' + ' RIGHT GROUP "Hebrew"\n' + ' RIGHT GLYPH "one.Hebr"\n' 'END_CONTEXT\n' 'IN_CONTEXT\n' - 'LEFT GROUP "Hebrew"\n' - 'LEFT GLYPH "one.Hebr"\n' + ' LEFT GROUP "Hebrew"\n' + ' LEFT GLYPH "one.Hebr"\n' 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GLYPH "dollar"\n' @@ -631,8 +646,9 @@ class ParserTest(unittest.TestCase): def test_substitution_skip_base(self): [group, lookup] = self.parse( - 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" ' - 'END_ENUM END_GROUP\n' + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n' + 'END_GROUP\n' 'DEF_LOOKUP "SomeSub" SKIP_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' 'IN_CONTEXT\n' @@ -649,8 +665,9 @@ class ParserTest(unittest.TestCase): def test_substitution_process_base(self): [group, lookup] = self.parse( - 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" ' - 'END_ENUM END_GROUP\n' + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n' + 'END_GROUP\n' 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' 'IN_CONTEXT\n' @@ -665,12 +682,74 @@ class ParserTest(unittest.TestCase): (lookup.name, lookup.process_base), ("SomeSub", True)) + def test_substitution_process_marks(self): + [group, lookup] = self.parse( + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n' + 'END_GROUP\n' + 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS "SomeMarks"\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' + 'AS_SUBSTITUTION\n' + 'SUB GLYPH "A"\n' + 'WITH GLYPH "A.c2sc"\n' + 'END_SUB\n' + 'END_SUBSTITUTION' + ).statements + self.assertEqual( + (lookup.name, lookup.process_marks), + ("SomeSub", 'SomeMarks')) + + def test_substitution_process_marks_all(self): + [lookup] = self.parse( + 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' + 'AS_SUBSTITUTION\n' + 'SUB GLYPH "A"\n' + 'WITH GLYPH "A.c2sc"\n' + 'END_SUB\n' + 'END_SUBSTITUTION' + ).statements + self.assertEqual( + (lookup.name, lookup.process_marks), + ("SomeSub", True)) + + def test_substitution_process_marks_none(self): + [lookup] = self.parse_( + 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS "NONE"\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' + 'AS_SUBSTITUTION\n' + 'SUB GLYPH "A"\n' + 'WITH GLYPH "A.c2sc"\n' + 'END_SUB\n' + 'END_SUBSTITUTION' + ).statements + self.assertEqual( + (lookup.name, lookup.process_marks), + ("SomeSub", False)) + + def test_substitution_process_marks_bad(self): + with self.assertRaisesRegex( + VoltLibError, + 'Expected ALL, NONE, MARK_GLYPH_SET or an ID'): + self.parse( + 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" ' + 'END_ENUM END_GROUP\n' + 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS SomeMarks ' + 'AS_SUBSTITUTION\n' + 'SUB GLYPH "A" WITH GLYPH "A.c2sc"\n' + 'END_SUB\n' + 'END_SUBSTITUTION' + ) + def test_substitution_skip_marks(self): [group, lookup] = self.parse( - 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" ' - 'END_ENUM END_GROUP\n' - 'DEF_LOOKUP "SomeSub" PROCESS_BASE SKIP_MARKS ' - 'DIRECTION LTR\n' + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n' + 'END_GROUP\n' + 'DEF_LOOKUP "SomeSub" PROCESS_BASE SKIP_MARKS DIRECTION LTR\n' 'IN_CONTEXT\n' 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' @@ -685,11 +764,13 @@ class ParserTest(unittest.TestCase): def test_substitution_mark_attachment(self): [group, lookup] = self.parse( - 'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" ' - 'END_ENUM END_GROUP\n' + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n' + 'END_GROUP\n' 'DEF_LOOKUP "SomeSub" PROCESS_BASE ' - 'PROCESS_MARKS "SomeMarks" \n' - 'DIRECTION RTL\n' + 'PROCESS_MARKS "SomeMarks" DIRECTION RTL\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GLYPH "A"\n' 'WITH GLYPH "A.c2sc"\n' @@ -702,11 +783,13 @@ class ParserTest(unittest.TestCase): def test_substitution_mark_glyph_set(self): [group, lookup] = self.parse( - 'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" ' - 'END_ENUM END_GROUP\n' + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n' + 'END_GROUP\n' 'DEF_LOOKUP "SomeSub" PROCESS_BASE ' - 'PROCESS_MARKS MARK_GLYPH_SET "SomeMarks" \n' - 'DIRECTION RTL\n' + 'PROCESS_MARKS MARK_GLYPH_SET "SomeMarks" DIRECTION RTL\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GLYPH "A"\n' 'WITH GLYPH "A.c2sc"\n' @@ -719,11 +802,13 @@ class ParserTest(unittest.TestCase): def test_substitution_process_all_marks(self): [group, lookup] = self.parse( - 'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" ' - 'END_ENUM END_GROUP\n' - 'DEF_LOOKUP "SomeSub" PROCESS_BASE ' - 'PROCESS_MARKS ALL \n' + 'DEF_GROUP "SomeMarks"\n' + ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n' + 'END_GROUP\n' + 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION RTL\n' + 'IN_CONTEXT\n' + 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GLYPH "A"\n' 'WITH GLYPH "A.c2sc"\n' @@ -740,7 +825,7 @@ class ParserTest(unittest.TestCase): 'DEF_LOOKUP "Lookup" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' 'IN_CONTEXT\n' - 'RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n' + ' RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n' 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GLYPH "a"\n' @@ -756,15 +841,15 @@ class ParserTest(unittest.TestCase): def test_substitution_reversal(self): lookup = self.parse( 'DEF_GROUP "DFLT_Num_standardFigures"\n' - 'ENUM GLYPH "zero" GLYPH "one" GLYPH "two" END_ENUM\n' + ' ENUM GLYPH "zero" GLYPH "one" GLYPH "two" END_ENUM\n' 'END_GROUP\n' 'DEF_GROUP "DFLT_Num_numerators"\n' - 'ENUM GLYPH "zero.numr" GLYPH "one.numr" GLYPH "two.numr" END_ENUM\n' + ' ENUM GLYPH "zero.numr" GLYPH "one.numr" GLYPH "two.numr" END_ENUM\n' 'END_GROUP\n' 'DEF_LOOKUP "RevLookup" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR REVERSAL\n' 'IN_CONTEXT\n' - 'RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n' + ' RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n' 'END_CONTEXT\n' 'AS_SUBSTITUTION\n' 'SUB GROUP "DFLT_Num_standardFigures"\n' @@ -820,7 +905,7 @@ class ParserTest(unittest.TestCase): 'DEF_LOOKUP "numr" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR REVERSAL\n' 'IN_CONTEXT\n' - 'RIGHT ENUM ' + ' RIGHT ENUM ' 'GLYPH "fraction" ' 'RANGE "zero.numr" TO "nine.numr" ' 'END_ENUM\n' @@ -861,7 +946,7 @@ class ParserTest(unittest.TestCase): 'DEF_LOOKUP "empty_position" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' 'EXCEPT_CONTEXT\n' - 'LEFT GLYPH "glyph"\n' + ' LEFT GLYPH "glyph"\n' 'END_CONTEXT\n' 'AS_POSITION\n' 'END_POSITION' @@ -880,13 +965,13 @@ class ParserTest(unittest.TestCase): 'END_ATTACH\n' 'END_POSITION\n' 'DEF_ANCHOR "MARK_top" ON 120 GLYPH acutecomb COMPONENT 1 ' - 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n' + 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "MARK_top" ON 121 GLYPH gravecomb COMPONENT 1 ' - 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n' + 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "top" ON 31 GLYPH a COMPONENT 1 ' - 'AT POS DX 210 DY 450 END_POS END_ANCHOR\n' + 'AT POS DX 210 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "top" ON 35 GLYPH e COMPONENT 1 ' - 'AT POS DX 215 DY 450 END_POS END_ANCHOR\n' + 'AT POS DX 215 DY 450 END_POS END_ANCHOR' ).statements pos = lookup.pos coverage = [g.glyph for g in pos.coverage] @@ -926,9 +1011,9 @@ class ParserTest(unittest.TestCase): 'IN_CONTEXT\n' 'END_CONTEXT\n' 'AS_POSITION\n' - 'ATTACH_CURSIVE EXIT GLYPH "a" GLYPH "b" ENTER GLYPH "c"\n' + 'ATTACH_CURSIVE\nEXIT GLYPH "a" GLYPH "b"\nENTER GLYPH "c"\n' 'END_ATTACH\n' - 'END_POSITION\n' + 'END_POSITION' ).statements exit = [[g.glyph for g in v] for v in lookup.pos.coverages_exit] enter = [[g.glyph for g in v] for v in lookup.pos.coverages_enter] @@ -945,12 +1030,12 @@ class ParserTest(unittest.TestCase): 'END_CONTEXT\n' 'AS_POSITION\n' 'ADJUST_PAIR\n' - ' FIRST GLYPH "A"\n' - ' SECOND GLYPH "V"\n' + ' FIRST GLYPH "A"\n' + ' SECOND GLYPH "V"\n' ' 1 2 BY POS ADV -30 END_POS POS END_POS\n' - ' 2 1 BY POS ADV -30 END_POS POS END_POS\n' + ' 2 1 BY POS ADV -30 END_POS POS END_POS\n\n' 'END_ADJUST\n' - 'END_POSITION\n' + 'END_POSITION' ).statements coverages_1 = [[g.glyph for g in v] for v in lookup.pos.coverages_1] coverages_2 = [[g.glyph for g in v] for v in lookup.pos.coverages_2] @@ -969,15 +1054,15 @@ class ParserTest(unittest.TestCase): 'DEF_LOOKUP "TestLookup" PROCESS_BASE PROCESS_MARKS ALL ' 'DIRECTION LTR\n' 'IN_CONTEXT\n' - # 'LEFT GLYPH "leftGlyph"\n' - # 'RIGHT GLYPH "rightGlyph"\n' + # ' LEFT GLYPH "leftGlyph"\n' + # ' RIGHT GLYPH "rightGlyph"\n' 'END_CONTEXT\n' 'AS_POSITION\n' 'ADJUST_SINGLE' - ' GLYPH "glyph1" BY POS ADV 0 DX 123 END_POS\n' + ' GLYPH "glyph1" BY POS ADV 0 DX 123 END_POS' ' GLYPH "glyph2" BY POS ADV 0 DX 456 END_POS\n' 'END_ADJUST\n' - 'END_POSITION\n' + 'END_POSITION' ).statements pos = lookup.pos adjust = [[[g.glyph for g in a], b] for (a, b) in pos.adjust_single] @@ -991,11 +1076,11 @@ class ParserTest(unittest.TestCase): def test_def_anchor(self): [anchor1, anchor2, anchor3] = self.parse( 'DEF_ANCHOR "top" ON 120 GLYPH a ' - 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "MARK_top" ON 120 GLYPH acutecomb ' - 'COMPONENT 1 AT POS DX 0 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 1 AT POS DX 0 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "bottom" ON 120 GLYPH a ' - 'COMPONENT 1 AT POS DX 250 DY 0 END_POS END_ANCHOR\n' + 'COMPONENT 1 AT POS DX 250 DY 0 END_POS END_ANCHOR' ).statements self.assertEqual( (anchor1.name, anchor1.gid, anchor1.glyph_name, anchor1.component, @@ -1019,9 +1104,9 @@ class ParserTest(unittest.TestCase): def test_def_anchor_multi_component(self): [anchor1, anchor2] = self.parse( 'DEF_ANCHOR "top" ON 120 GLYPH a ' - 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "top" ON 120 GLYPH a ' - 'COMPONENT 2 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 2 AT POS DX 250 DY 450 END_POS END_ANCHOR' ).statements self.assertEqual( (anchor1.name, anchor1.gid, anchor1.glyph_name, anchor1.component), @@ -1039,15 +1124,15 @@ class ParserTest(unittest.TestCase): 'anchor names are case insensitive', self.parse, 'DEF_ANCHOR "dupe" ON 120 GLYPH a ' - 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' 'DEF_ANCHOR "dupe" ON 120 GLYPH a ' - 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR' ) def test_def_anchor_locked(self): [anchor] = self.parse( 'DEF_ANCHOR "top" ON 120 GLYPH a ' - 'COMPONENT 1 LOCKED AT POS DX 250 DY 450 END_POS END_ANCHOR\n' + 'COMPONENT 1 LOCKED AT POS DX 250 DY 450 END_POS END_ANCHOR' ).statements self.assertEqual( (anchor.name, anchor.gid, anchor.glyph_name, anchor.component, @@ -1059,7 +1144,7 @@ class ParserTest(unittest.TestCase): def test_anchor_adjust_device(self): [anchor] = self.parse( 'DEF_ANCHOR "MARK_top" ON 123 GLYPH diacglyph ' - 'COMPONENT 1 AT POS DX 0 DY 456 ADJUST_BY 12 AT 34 ' + 'COMPONENT 1 AT POS DX 0 DY 456 ADJUST_BY 12 AT 34 ' 'ADJUST_BY 56 AT 78 END_POS END_ANCHOR' ).statements self.assertEqual( @@ -1071,7 +1156,7 @@ class ParserTest(unittest.TestCase): [grid_ppem, pres_ppem, ppos_ppem] = self.parse( 'GRID_PPEM 20\n' 'PRESENTATION_PPEM 72\n' - 'PPOSITIONING_PPEM 144\n' + 'PPOSITIONING_PPEM 144' ).statements self.assertEqual( ((grid_ppem.name, grid_ppem.value), @@ -1084,7 +1169,7 @@ class ParserTest(unittest.TestCase): def test_compiler_flags(self): [setting1, setting2] = self.parse( 'COMPILER_USEEXTENSIONLOOKUPS\n' - 'COMPILER_USEPAIRPOSFORMAT2\n' + 'COMPILER_USEPAIRPOSFORMAT2' ).statements self.assertEqual( ((setting1.name, setting1.value), @@ -1097,7 +1182,7 @@ class ParserTest(unittest.TestCase): [cmap_format1, cmap_format2, cmap_format3] = self.parse( 'CMAP_FORMAT 0 3 4\n' 'CMAP_FORMAT 1 0 6\n' - 'CMAP_FORMAT 3 1 4\n' + 'CMAP_FORMAT 3 1 4' ).statements self.assertEqual( ((cmap_format1.name, cmap_format1.value), @@ -1108,16 +1193,42 @@ class ParserTest(unittest.TestCase): ("CMAP_FORMAT", (3, 1, 4))) ) + def test_do_not_touch_cmap(self): + [option1, option2, option3, option4] = self.parse( + 'DO_NOT_TOUCH_CMAP\n' + 'CMAP_FORMAT 0 3 4\n' + 'CMAP_FORMAT 1 0 6\n' + 'CMAP_FORMAT 3 1 4' + ).statements + self.assertEqual( + ((option1.name, option1.value), + (option2.name, option2.value), + (option3.name, option3.value), + (option4.name, option4.value)), + (("DO_NOT_TOUCH_CMAP", True), + ("CMAP_FORMAT", (0, 3, 4)), + ("CMAP_FORMAT", (1, 0, 6)), + ("CMAP_FORMAT", (3, 1, 4))) + ) + def test_stop_at_end(self): - [def_glyph] = self.parse( + doc = self.parse_( 'DEF_GLYPH ".notdef" ID 0 TYPE BASE END_GLYPH END\0\0\0\0' - ).statements + ) + [def_glyph] = doc.statements self.assertEqual((def_glyph.name, def_glyph.id, def_glyph.unicode, def_glyph.type, def_glyph.components), (".notdef", 0, None, "BASE", None)) + self.assertEqual(str(doc), + '\nDEF_GLYPH ".notdef" ID 0 TYPE BASE END_GLYPH END\n') + + def parse_(self, text): + return Parser(StringIO(text)).parse() def parse(self, text): - return Parser(UnicodeIO(text)).parse() + doc = self.parse_(text) + self.assertEqual('\n'.join(str(s) for s in doc.statements), text) + return Parser(StringIO(text)).parse() if __name__ == "__main__": import sys |