2017-01-26 19:29:05 +00:00
|
|
|
from fontTools.ttLib import TTFont, tagToXML
|
2021-03-29 11:45:58 +02:00
|
|
|
from io import StringIO
|
2017-01-25 18:22:53 -08:00
|
|
|
import os
|
|
|
|
import sys
|
2017-01-26 19:29:05 +00:00
|
|
|
import re
|
|
|
|
import contextlib
|
|
|
|
import pytest
|
2017-01-25 18:22:53 -08:00
|
|
|
|
2017-03-02 13:34:39 +00:00
|
|
|
try:
|
|
|
|
import unicodedata2
|
|
|
|
except ImportError:
|
|
|
|
if sys.version_info[:2] < (3, 6):
|
|
|
|
unicodedata2 = None
|
|
|
|
else:
|
|
|
|
# on 3.6 the built-in unicodedata is the same as unicodedata2 backport
|
|
|
|
import unicodedata
|
2022-12-13 11:26:36 +00:00
|
|
|
|
2017-03-02 13:34:39 +00:00
|
|
|
unicodedata2 = unicodedata
|
|
|
|
|
2017-01-25 18:22:53 -08:00
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
# Font files in data/*.{o,t}tf; output gets compared to data/*.ttx.*
|
|
|
|
TESTS = {
|
2022-12-13 11:26:36 +00:00
|
|
|
"aots/base.otf": (
|
|
|
|
"CFF ",
|
|
|
|
"cmap",
|
|
|
|
"head",
|
|
|
|
"hhea",
|
|
|
|
"hmtx",
|
|
|
|
"maxp",
|
|
|
|
"name",
|
|
|
|
"OS/2",
|
|
|
|
"post",
|
|
|
|
),
|
|
|
|
"aots/classdef1_font1.otf": ("GSUB",),
|
|
|
|
"aots/classdef1_font2.otf": ("GSUB",),
|
|
|
|
"aots/classdef1_font3.otf": ("GSUB",),
|
|
|
|
"aots/classdef1_font4.otf": ("GSUB",),
|
|
|
|
"aots/classdef2_font1.otf": ("GSUB",),
|
|
|
|
"aots/classdef2_font2.otf": ("GSUB",),
|
|
|
|
"aots/classdef2_font3.otf": ("GSUB",),
|
|
|
|
"aots/classdef2_font4.otf": ("GSUB",),
|
|
|
|
"aots/cmap0_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap10_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap10_font2.otf": ("cmap",),
|
|
|
|
"aots/cmap12_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap14_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap2_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap4_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap4_font2.otf": ("cmap",),
|
|
|
|
"aots/cmap4_font3.otf": ("cmap",),
|
|
|
|
"aots/cmap4_font4.otf": ("cmap",),
|
|
|
|
"aots/cmap6_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap6_font2.otf": ("cmap",),
|
|
|
|
"aots/cmap8_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap_composition_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap_subtableselection_font1.otf": ("cmap",),
|
|
|
|
"aots/cmap_subtableselection_font2.otf": ("cmap",),
|
|
|
|
"aots/cmap_subtableselection_font3.otf": ("cmap",),
|
|
|
|
"aots/cmap_subtableselection_font4.otf": ("cmap",),
|
|
|
|
"aots/cmap_subtableselection_font5.otf": ("cmap",),
|
|
|
|
"aots/gpos1_1_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos1_1_simple_f1.otf": ("GPOS",),
|
|
|
|
"aots/gpos1_1_simple_f2.otf": ("GPOS",),
|
|
|
|
"aots/gpos1_1_simple_f3.otf": ("GPOS",),
|
|
|
|
"aots/gpos1_1_simple_f4.otf": ("GPOS",),
|
|
|
|
"aots/gpos1_2_font1.otf": ("GPOS",),
|
|
|
|
"aots/gpos1_2_font2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos2_1_font6.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_1_font7.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_1_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos2_1_lookupflag_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos2_1_next_glyph_f1.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_1_next_glyph_f2.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_1_simple_f1.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_2_font1.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_2_font2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos2_2_font3.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos2_2_font4.otf": ("GPOS",),
|
|
|
|
"aots/gpos2_2_font5.otf": ("GPOS",),
|
|
|
|
"aots/gpos3_font1.otf": ("GPOS",),
|
|
|
|
"aots/gpos3_font2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos3_font3.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos4_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos4_lookupflag_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos4_multiple_anchors_1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos4_simple_1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos5_font1.otf": ("GDEF", "GPOS", "GSUB"),
|
|
|
|
"aots/gpos6_font1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos7_1_font1.otf": ("GPOS",),
|
|
|
|
"aots/gpos9_font1.otf": ("GPOS",),
|
|
|
|
"aots/gpos9_font2.otf": ("GPOS",),
|
|
|
|
"aots/gpos_chaining1_boundary_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_boundary_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_boundary_f3.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_boundary_f4.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_multiple_subrules_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_multiple_subrules_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_next_glyph_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_simple_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_simple_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining1_successive_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_boundary_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_boundary_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_boundary_f3.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_boundary_f4.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_multiple_subrules_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_multiple_subrules_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_next_glyph_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_simple_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_simple_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining2_successive_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_boundary_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_boundary_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_boundary_f3.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_boundary_f4.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_next_glyph_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_simple_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_simple_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_chaining3_successive_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_boundary_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_boundary_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_expansion_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_lookupflag_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_multiple_subrules_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_multiple_subrules_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_next_glyph_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_simple_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_simple_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context1_successive_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_boundary_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_boundary_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_classes_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_classes_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_expansion_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_lookupflag_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_multiple_subrules_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_multiple_subrules_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_next_glyph_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_simple_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_simple_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context2_successive_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_boundary_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_boundary_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_lookupflag_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_lookupflag_f2.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_next_glyph_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_simple_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gpos_context3_successive_f1.otf": ("GDEF", "GPOS"),
|
|
|
|
"aots/gsub1_1_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub1_1_modulo_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub1_1_simple_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub1_2_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub1_2_simple_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub2_1_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub2_1_multiple_sequences_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub2_1_simple_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub3_1_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub3_1_multiple_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub3_1_simple_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub4_1_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub4_1_multiple_ligatures_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub4_1_multiple_ligatures_f2.otf": ("GSUB",),
|
|
|
|
"aots/gsub4_1_multiple_ligsets_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub4_1_simple_f1.otf": ("GSUB",),
|
|
|
|
"aots/gsub7_font1.otf": ("GSUB",),
|
|
|
|
"aots/gsub7_font2.otf": ("GSUB",),
|
|
|
|
"aots/gsub_chaining1_boundary_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_boundary_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_boundary_f3.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_boundary_f4.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_multiple_subrules_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_multiple_subrules_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_next_glyph_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_simple_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_simple_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining1_successive_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_boundary_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_boundary_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_boundary_f3.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_boundary_f4.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_multiple_subrules_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_multiple_subrules_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_next_glyph_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_simple_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_simple_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining2_successive_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_boundary_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_boundary_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_boundary_f3.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_boundary_f4.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_next_glyph_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_simple_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_simple_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_chaining3_successive_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_boundary_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_boundary_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_expansion_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_lookupflag_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_multiple_subrules_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_multiple_subrules_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_next_glyph_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_simple_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_simple_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context1_successive_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_boundary_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_boundary_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_classes_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_classes_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_expansion_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_lookupflag_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_multiple_subrules_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_multiple_subrules_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_next_glyph_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_simple_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_simple_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context2_successive_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_boundary_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_boundary_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_lookupflag_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_lookupflag_f2.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_next_glyph_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_simple_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/gsub_context3_successive_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/lookupflag_ignore_attach_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/lookupflag_ignore_base_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/lookupflag_ignore_combination_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/lookupflag_ignore_ligatures_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"aots/lookupflag_ignore_marks_f1.otf": ("GDEF", "GSUB"),
|
|
|
|
"graphite/graphite_tests.ttf": ("Silf", "Glat", "Feat", "Sill"),
|
2017-01-26 19:29:05 +00:00
|
|
|
}
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-03-02 13:34:39 +00:00
|
|
|
TEST_REQUIREMENTS = {
|
2022-12-13 11:26:36 +00:00
|
|
|
"aots/cmap4_font4.otf": ("unicodedata2",),
|
2017-03-02 13:34:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
ttLibVersion_RE = re.compile(r' ttLibVersion=".*"')
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def getpath(testfile):
|
|
|
|
path = os.path.dirname(__file__)
|
|
|
|
return os.path.join(path, "data", testfile)
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def read_expected_ttx(testfile, tableTag):
|
|
|
|
name = os.path.splitext(testfile)[0]
|
|
|
|
xml_expected_path = getpath("%s.ttx.%s" % (name, tagToXML(tableTag)))
|
2022-12-13 11:26:36 +00:00
|
|
|
with open(xml_expected_path, "r", encoding="utf-8") as xml_file:
|
|
|
|
xml_expected = ttLibVersion_RE.sub("", xml_file.read())
|
2017-01-26 19:29:05 +00:00
|
|
|
return xml_expected
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def dump_ttx(font, tableTag):
|
2021-03-29 11:45:58 +02:00
|
|
|
f = StringIO()
|
2021-07-30 03:58:20 +02:00
|
|
|
font.saveXML(f, tables=[tableTag])
|
2022-12-13 11:26:36 +00:00
|
|
|
return ttLibVersion_RE.sub("", f.getvalue())
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def load_ttx(ttx):
|
2021-03-29 11:45:58 +02:00
|
|
|
f = StringIO()
|
2017-01-26 19:29:05 +00:00
|
|
|
f.write(ttx)
|
|
|
|
f.seek(0)
|
|
|
|
font = TTFont()
|
|
|
|
font.importXML(f)
|
|
|
|
return font
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
@contextlib.contextmanager
|
|
|
|
def open_font(testfile):
|
|
|
|
font = TTFont(getpath(testfile))
|
|
|
|
try:
|
|
|
|
yield font
|
|
|
|
finally:
|
|
|
|
font.close()
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-03-02 13:34:39 +00:00
|
|
|
def _skip_if_requirement_missing(testfile):
|
|
|
|
if testfile in TEST_REQUIREMENTS:
|
|
|
|
for req in TEST_REQUIREMENTS[testfile]:
|
|
|
|
if globals()[req] is None:
|
2022-12-13 11:26:36 +00:00
|
|
|
pytest.skip("%s not installed" % req)
|
2017-03-02 13:34:39 +00:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def test_xml_from_binary(testfile, tableTag):
|
2017-03-13 11:28:39 +00:00
|
|
|
"""Check XML from decompiled object."""
|
2017-03-02 13:34:39 +00:00
|
|
|
_skip_if_requirement_missing(testfile)
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
xml_expected = read_expected_ttx(testfile, tableTag)
|
2017-01-25 18:22:53 -08:00
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
with open_font(testfile) as font:
|
|
|
|
xml_from_binary = dump_ttx(font, tableTag)
|
2017-01-25 18:22:53 -08:00
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
assert xml_expected == xml_from_binary
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def test_xml_from_xml(testfile, tableTag):
|
2017-03-13 11:28:39 +00:00
|
|
|
"""Check XML from object read from XML."""
|
2017-03-02 13:34:39 +00:00
|
|
|
_skip_if_requirement_missing(testfile)
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
xml_expected = read_expected_ttx(testfile, tableTag)
|
2017-01-25 18:22:53 -08:00
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
font = load_ttx(xml_expected)
|
2017-09-15 11:18:44 +07:00
|
|
|
name = os.path.splitext(testfile)[0]
|
|
|
|
setupfile = getpath("%s.ttx.%s.setup" % (name, tagToXML(tableTag)))
|
|
|
|
if os.path.exists(setupfile):
|
2022-12-13 11:26:36 +00:00
|
|
|
# import pdb; pdb.set_trace()
|
2017-09-15 11:18:44 +07:00
|
|
|
font.importXML(setupfile)
|
2017-01-26 19:29:05 +00:00
|
|
|
xml_from_xml = dump_ttx(font, tableTag)
|
2017-01-25 18:22:53 -08:00
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
assert xml_expected == xml_from_xml
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2017-01-26 19:29:05 +00:00
|
|
|
def pytest_generate_tests(metafunc):
|
|
|
|
# http://doc.pytest.org/en/latest/parametrize.html#basic-pytest-generate-tests-example
|
|
|
|
fixturenames = metafunc.fixturenames
|
|
|
|
argnames = ("testfile", "tableTag")
|
|
|
|
if all(fn in fixturenames for fn in argnames):
|
2022-12-13 11:26:36 +00:00
|
|
|
argvalues = [
|
|
|
|
(testfile, tableTag)
|
|
|
|
for testfile, tableTags in sorted(TESTS.items())
|
|
|
|
for tableTag in tableTags
|
|
|
|
]
|
2017-01-26 19:29:05 +00:00
|
|
|
metafunc.parametrize(argnames, argvalues)
|
2017-01-25 18:22:53 -08:00
|
|
|
|
|
|
|
|
2022-12-13 11:26:36 +00:00
|
|
|
if __name__ == "__main__":
|
2017-01-26 19:29:05 +00:00
|
|
|
sys.exit(pytest.main(sys.argv))
|