xref: /aosp_15_r20/external/fonttools/Tests/designspaceLib/designspace_v5_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughesimport re
2*e1fe3e4aSElliott Hughesimport shutil
3*e1fe3e4aSElliott Hughesfrom pathlib import Path
4*e1fe3e4aSElliott Hughes
5*e1fe3e4aSElliott Hughesimport pytest
6*e1fe3e4aSElliott Hughesfrom fontTools.designspaceLib import (
7*e1fe3e4aSElliott Hughes    AxisDescriptor,
8*e1fe3e4aSElliott Hughes    AxisLabelDescriptor,
9*e1fe3e4aSElliott Hughes    DesignSpaceDocument,
10*e1fe3e4aSElliott Hughes    DiscreteAxisDescriptor,
11*e1fe3e4aSElliott Hughes    InstanceDescriptor,
12*e1fe3e4aSElliott Hughes    LocationLabelDescriptor,
13*e1fe3e4aSElliott Hughes    RangeAxisSubsetDescriptor,
14*e1fe3e4aSElliott Hughes    SourceDescriptor,
15*e1fe3e4aSElliott Hughes    ValueAxisSubsetDescriptor,
16*e1fe3e4aSElliott Hughes    VariableFontDescriptor,
17*e1fe3e4aSElliott Hughes    posix,
18*e1fe3e4aSElliott Hughes)
19*e1fe3e4aSElliott Hughes
20*e1fe3e4aSElliott Hughesfrom .fixtures import datadir
21*e1fe3e4aSElliott Hughes
22*e1fe3e4aSElliott Hughes
23*e1fe3e4aSElliott Hughesdef assert_descriptors_equal(actual, expected):
24*e1fe3e4aSElliott Hughes    assert len(actual) == len(expected)
25*e1fe3e4aSElliott Hughes    for a, e in zip(actual, expected):
26*e1fe3e4aSElliott Hughes        assert a.asdict() == e.asdict()
27*e1fe3e4aSElliott Hughes
28*e1fe3e4aSElliott Hughes
29*e1fe3e4aSElliott Hughesdef test_read_v5_document_simple(datadir):
30*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace")
31*e1fe3e4aSElliott Hughes
32*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
33*e1fe3e4aSElliott Hughes        doc.axes,
34*e1fe3e4aSElliott Hughes        [
35*e1fe3e4aSElliott Hughes            AxisDescriptor(
36*e1fe3e4aSElliott Hughes                tag="wght",
37*e1fe3e4aSElliott Hughes                name="Weight",
38*e1fe3e4aSElliott Hughes                minimum=200,
39*e1fe3e4aSElliott Hughes                maximum=1000,
40*e1fe3e4aSElliott Hughes                default=200,
41*e1fe3e4aSElliott Hughes                labelNames={"en": "Wéíght", "fa-IR": "قطر"},
42*e1fe3e4aSElliott Hughes                map=[
43*e1fe3e4aSElliott Hughes                    (200, 0),
44*e1fe3e4aSElliott Hughes                    (300, 100),
45*e1fe3e4aSElliott Hughes                    (400, 368),
46*e1fe3e4aSElliott Hughes                    (600, 600),
47*e1fe3e4aSElliott Hughes                    (700, 824),
48*e1fe3e4aSElliott Hughes                    (900, 1000),
49*e1fe3e4aSElliott Hughes                ],
50*e1fe3e4aSElliott Hughes                axisOrdering=None,
51*e1fe3e4aSElliott Hughes                axisLabels=[
52*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
53*e1fe3e4aSElliott Hughes                        name="Extra Light",
54*e1fe3e4aSElliott Hughes                        userMinimum=200,
55*e1fe3e4aSElliott Hughes                        userValue=200,
56*e1fe3e4aSElliott Hughes                        userMaximum=250,
57*e1fe3e4aSElliott Hughes                        labelNames={"de": "Extraleicht", "fr": "Extra léger"},
58*e1fe3e4aSElliott Hughes                    ),
59*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
60*e1fe3e4aSElliott Hughes                        name="Light", userMinimum=250, userValue=300, userMaximum=350
61*e1fe3e4aSElliott Hughes                    ),
62*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
63*e1fe3e4aSElliott Hughes                        name="Regular",
64*e1fe3e4aSElliott Hughes                        userMinimum=350,
65*e1fe3e4aSElliott Hughes                        userValue=400,
66*e1fe3e4aSElliott Hughes                        userMaximum=450,
67*e1fe3e4aSElliott Hughes                        elidable=True,
68*e1fe3e4aSElliott Hughes                    ),
69*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
70*e1fe3e4aSElliott Hughes                        name="Semi Bold",
71*e1fe3e4aSElliott Hughes                        userMinimum=450,
72*e1fe3e4aSElliott Hughes                        userValue=600,
73*e1fe3e4aSElliott Hughes                        userMaximum=650,
74*e1fe3e4aSElliott Hughes                    ),
75*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
76*e1fe3e4aSElliott Hughes                        name="Bold", userMinimum=650, userValue=700, userMaximum=850
77*e1fe3e4aSElliott Hughes                    ),
78*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
79*e1fe3e4aSElliott Hughes                        name="Black", userMinimum=850, userValue=900, userMaximum=900
80*e1fe3e4aSElliott Hughes                    ),
81*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
82*e1fe3e4aSElliott Hughes                        name="Regular",
83*e1fe3e4aSElliott Hughes                        userValue=400,
84*e1fe3e4aSElliott Hughes                        linkedUserValue=700,
85*e1fe3e4aSElliott Hughes                        elidable=True,
86*e1fe3e4aSElliott Hughes                    ),
87*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
88*e1fe3e4aSElliott Hughes                        name="Bold", userValue=700, linkedUserValue=400
89*e1fe3e4aSElliott Hughes                    ),
90*e1fe3e4aSElliott Hughes                ],
91*e1fe3e4aSElliott Hughes            ),
92*e1fe3e4aSElliott Hughes            AxisDescriptor(
93*e1fe3e4aSElliott Hughes                tag="wdth",
94*e1fe3e4aSElliott Hughes                name="Width",
95*e1fe3e4aSElliott Hughes                minimum=50,
96*e1fe3e4aSElliott Hughes                maximum=150,
97*e1fe3e4aSElliott Hughes                default=100,
98*e1fe3e4aSElliott Hughes                hidden=True,
99*e1fe3e4aSElliott Hughes                labelNames={"fr": "Chasse"},
100*e1fe3e4aSElliott Hughes                map=[(50, 10), (100, 20), (125, 66), (150, 990)],
101*e1fe3e4aSElliott Hughes                axisOrdering=1,
102*e1fe3e4aSElliott Hughes                axisLabels=[
103*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Condensed", userValue=50),
104*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
105*e1fe3e4aSElliott Hughes                        name="Normal", elidable=True, olderSibling=True, userValue=100
106*e1fe3e4aSElliott Hughes                    ),
107*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Wide", userValue=125),
108*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
109*e1fe3e4aSElliott Hughes                        name="Extra Wide", userValue=150, userMinimum=150
110*e1fe3e4aSElliott Hughes                    ),
111*e1fe3e4aSElliott Hughes                ],
112*e1fe3e4aSElliott Hughes            ),
113*e1fe3e4aSElliott Hughes            DiscreteAxisDescriptor(
114*e1fe3e4aSElliott Hughes                tag="ital",
115*e1fe3e4aSElliott Hughes                name="Italic",
116*e1fe3e4aSElliott Hughes                values=[0, 1],
117*e1fe3e4aSElliott Hughes                default=0,
118*e1fe3e4aSElliott Hughes                axisOrdering=None,
119*e1fe3e4aSElliott Hughes                axisLabels=[
120*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
121*e1fe3e4aSElliott Hughes                        name="Roman", userValue=0, elidable=True, linkedUserValue=1
122*e1fe3e4aSElliott Hughes                    ),
123*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Italic", userValue=1),
124*e1fe3e4aSElliott Hughes                ],
125*e1fe3e4aSElliott Hughes            ),
126*e1fe3e4aSElliott Hughes        ],
127*e1fe3e4aSElliott Hughes    )
128*e1fe3e4aSElliott Hughes
129*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
130*e1fe3e4aSElliott Hughes        doc.locationLabels,
131*e1fe3e4aSElliott Hughes        [
132*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
133*e1fe3e4aSElliott Hughes                name="Some Style",
134*e1fe3e4aSElliott Hughes                labelNames={"fr": "Un Style"},
135*e1fe3e4aSElliott Hughes                userLocation={"Weight": 300, "Width": 50, "Italic": 0},
136*e1fe3e4aSElliott Hughes            ),
137*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
138*e1fe3e4aSElliott Hughes                name="Other", userLocation={"Weight": 700, "Width": 100, "Italic": 1}
139*e1fe3e4aSElliott Hughes            ),
140*e1fe3e4aSElliott Hughes        ],
141*e1fe3e4aSElliott Hughes    )
142*e1fe3e4aSElliott Hughes
143*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
144*e1fe3e4aSElliott Hughes        doc.sources,
145*e1fe3e4aSElliott Hughes        [
146*e1fe3e4aSElliott Hughes            SourceDescriptor(
147*e1fe3e4aSElliott Hughes                filename="masters/masterTest1.ufo",
148*e1fe3e4aSElliott Hughes                path=posix(str((datadir / "masters/masterTest1.ufo").resolve())),
149*e1fe3e4aSElliott Hughes                name="master.ufo1",
150*e1fe3e4aSElliott Hughes                layerName=None,
151*e1fe3e4aSElliott Hughes                location={"Italic": 0.0, "Weight": 0.0, "Width": 20.0},
152*e1fe3e4aSElliott Hughes                copyLib=True,
153*e1fe3e4aSElliott Hughes                copyInfo=True,
154*e1fe3e4aSElliott Hughes                copyGroups=False,
155*e1fe3e4aSElliott Hughes                copyFeatures=True,
156*e1fe3e4aSElliott Hughes                muteKerning=False,
157*e1fe3e4aSElliott Hughes                muteInfo=False,
158*e1fe3e4aSElliott Hughes                mutedGlyphNames=["A", "Z"],
159*e1fe3e4aSElliott Hughes                familyName="MasterFamilyName",
160*e1fe3e4aSElliott Hughes                styleName="MasterStyleNameOne",
161*e1fe3e4aSElliott Hughes                localisedFamilyName={"fr": "Montserrat", "ja": "モンセラート"},
162*e1fe3e4aSElliott Hughes            ),
163*e1fe3e4aSElliott Hughes            SourceDescriptor(
164*e1fe3e4aSElliott Hughes                filename="masters/masterTest2.ufo",
165*e1fe3e4aSElliott Hughes                path=posix(str((datadir / "masters/masterTest2.ufo").resolve())),
166*e1fe3e4aSElliott Hughes                name="master.ufo2",
167*e1fe3e4aSElliott Hughes                layerName=None,
168*e1fe3e4aSElliott Hughes                location={"Italic": 0.0, "Weight": 1000.0, "Width": 20.0},
169*e1fe3e4aSElliott Hughes                copyLib=False,
170*e1fe3e4aSElliott Hughes                copyInfo=False,
171*e1fe3e4aSElliott Hughes                copyGroups=False,
172*e1fe3e4aSElliott Hughes                copyFeatures=False,
173*e1fe3e4aSElliott Hughes                muteKerning=True,
174*e1fe3e4aSElliott Hughes                muteInfo=False,
175*e1fe3e4aSElliott Hughes                mutedGlyphNames=[],
176*e1fe3e4aSElliott Hughes                familyName="MasterFamilyName",
177*e1fe3e4aSElliott Hughes                styleName="MasterStyleNameTwo",
178*e1fe3e4aSElliott Hughes                localisedFamilyName={},
179*e1fe3e4aSElliott Hughes            ),
180*e1fe3e4aSElliott Hughes            SourceDescriptor(
181*e1fe3e4aSElliott Hughes                filename="masters/masterTest2.ufo",
182*e1fe3e4aSElliott Hughes                path=posix(str((datadir / "masters/masterTest2.ufo").resolve())),
183*e1fe3e4aSElliott Hughes                name="master.ufo2",
184*e1fe3e4aSElliott Hughes                layerName="supports",
185*e1fe3e4aSElliott Hughes                location={"Italic": 0.0, "Weight": 1000.0, "Width": 20.0},
186*e1fe3e4aSElliott Hughes                copyLib=False,
187*e1fe3e4aSElliott Hughes                copyInfo=False,
188*e1fe3e4aSElliott Hughes                copyGroups=False,
189*e1fe3e4aSElliott Hughes                copyFeatures=False,
190*e1fe3e4aSElliott Hughes                muteKerning=False,
191*e1fe3e4aSElliott Hughes                muteInfo=False,
192*e1fe3e4aSElliott Hughes                mutedGlyphNames=[],
193*e1fe3e4aSElliott Hughes                familyName="MasterFamilyName",
194*e1fe3e4aSElliott Hughes                styleName="Supports",
195*e1fe3e4aSElliott Hughes                localisedFamilyName={},
196*e1fe3e4aSElliott Hughes            ),
197*e1fe3e4aSElliott Hughes            SourceDescriptor(
198*e1fe3e4aSElliott Hughes                filename="masters/masterTest2.ufo",
199*e1fe3e4aSElliott Hughes                path=posix(str((datadir / "masters/masterTest2.ufo").resolve())),
200*e1fe3e4aSElliott Hughes                name="master.ufo3",
201*e1fe3e4aSElliott Hughes                layerName=None,
202*e1fe3e4aSElliott Hughes                location={"Italic": 1.0, "Weight": 0.0, "Width": 100.0},
203*e1fe3e4aSElliott Hughes                copyLib=False,
204*e1fe3e4aSElliott Hughes                copyGroups=False,
205*e1fe3e4aSElliott Hughes                copyFeatures=False,
206*e1fe3e4aSElliott Hughes                muteKerning=False,
207*e1fe3e4aSElliott Hughes                muteInfo=False,
208*e1fe3e4aSElliott Hughes                mutedGlyphNames=[],
209*e1fe3e4aSElliott Hughes                familyName="MasterFamilyName",
210*e1fe3e4aSElliott Hughes                styleName="FauxItalic",
211*e1fe3e4aSElliott Hughes                localisedFamilyName={},
212*e1fe3e4aSElliott Hughes            ),
213*e1fe3e4aSElliott Hughes        ],
214*e1fe3e4aSElliott Hughes    )
215*e1fe3e4aSElliott Hughes
216*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
217*e1fe3e4aSElliott Hughes        doc.variableFonts,
218*e1fe3e4aSElliott Hughes        [
219*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
220*e1fe3e4aSElliott Hughes                name="Test_WghtWdth",
221*e1fe3e4aSElliott Hughes                filename="Test_WghtWdth_different_from_name.ttf",
222*e1fe3e4aSElliott Hughes                axisSubsets=[
223*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
224*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Width"),
225*e1fe3e4aSElliott Hughes                ],
226*e1fe3e4aSElliott Hughes                lib={"com.vtt.source": "sources/vtt/Test_WghtWdth.vtt"},
227*e1fe3e4aSElliott Hughes            ),
228*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
229*e1fe3e4aSElliott Hughes                name="Test_Wght",
230*e1fe3e4aSElliott Hughes                axisSubsets=[RangeAxisSubsetDescriptor(name="Weight")],
231*e1fe3e4aSElliott Hughes                lib={"com.vtt.source": "sources/vtt/Test_Wght.vtt"},
232*e1fe3e4aSElliott Hughes            ),
233*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
234*e1fe3e4aSElliott Hughes                name="TestCd_Wght",
235*e1fe3e4aSElliott Hughes                axisSubsets=[
236*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
237*e1fe3e4aSElliott Hughes                    ValueAxisSubsetDescriptor(name="Width", userValue=0),
238*e1fe3e4aSElliott Hughes                ],
239*e1fe3e4aSElliott Hughes            ),
240*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
241*e1fe3e4aSElliott Hughes                name="TestWd_Wght",
242*e1fe3e4aSElliott Hughes                axisSubsets=[
243*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
244*e1fe3e4aSElliott Hughes                    ValueAxisSubsetDescriptor(name="Width", userValue=1000),
245*e1fe3e4aSElliott Hughes                ],
246*e1fe3e4aSElliott Hughes            ),
247*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
248*e1fe3e4aSElliott Hughes                name="TestItalic_Wght",
249*e1fe3e4aSElliott Hughes                axisSubsets=[
250*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
251*e1fe3e4aSElliott Hughes                    ValueAxisSubsetDescriptor(name="Italic", userValue=1),
252*e1fe3e4aSElliott Hughes                ],
253*e1fe3e4aSElliott Hughes            ),
254*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
255*e1fe3e4aSElliott Hughes                name="TestRB_Wght",
256*e1fe3e4aSElliott Hughes                axisSubsets=[
257*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(
258*e1fe3e4aSElliott Hughes                        name="Weight", userMinimum=400, userDefault=400, userMaximum=700
259*e1fe3e4aSElliott Hughes                    ),
260*e1fe3e4aSElliott Hughes                    ValueAxisSubsetDescriptor(name="Italic", userValue=0),
261*e1fe3e4aSElliott Hughes                ],
262*e1fe3e4aSElliott Hughes            ),
263*e1fe3e4aSElliott Hughes        ],
264*e1fe3e4aSElliott Hughes    )
265*e1fe3e4aSElliott Hughes
266*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
267*e1fe3e4aSElliott Hughes        doc.instances,
268*e1fe3e4aSElliott Hughes        [
269*e1fe3e4aSElliott Hughes            InstanceDescriptor(
270*e1fe3e4aSElliott Hughes                filename="instances/instanceTest1.ufo",
271*e1fe3e4aSElliott Hughes                path=posix(str((datadir / "instances/instanceTest1.ufo").resolve())),
272*e1fe3e4aSElliott Hughes                name="instance.ufo1",
273*e1fe3e4aSElliott Hughes                designLocation={"Weight": 500.0, "Width": 20.0},
274*e1fe3e4aSElliott Hughes                familyName="InstanceFamilyName",
275*e1fe3e4aSElliott Hughes                styleName="InstanceStyleName",
276*e1fe3e4aSElliott Hughes                postScriptFontName="InstancePostscriptName",
277*e1fe3e4aSElliott Hughes                styleMapFamilyName="InstanceStyleMapFamilyName",
278*e1fe3e4aSElliott Hughes                styleMapStyleName="InstanceStyleMapStyleName",
279*e1fe3e4aSElliott Hughes                localisedFamilyName={"fr": "Montserrat", "ja": "モンセラート"},
280*e1fe3e4aSElliott Hughes                localisedStyleName={"fr": "Demigras", "ja": "半ば"},
281*e1fe3e4aSElliott Hughes                localisedStyleMapFamilyName={
282*e1fe3e4aSElliott Hughes                    "de": "Montserrat Halbfett",
283*e1fe3e4aSElliott Hughes                    "ja": "モンセラート SemiBold",
284*e1fe3e4aSElliott Hughes                },
285*e1fe3e4aSElliott Hughes                localisedStyleMapStyleName={"de": "Standard"},
286*e1fe3e4aSElliott Hughes                glyphs={"arrow": {"mute": True, "unicodes": [291, 292, 293]}},
287*e1fe3e4aSElliott Hughes                lib={
288*e1fe3e4aSElliott Hughes                    "com.coolDesignspaceApp.binaryData": b"<binary gunk>",
289*e1fe3e4aSElliott Hughes                    "com.coolDesignspaceApp.specimenText": "Hamburgerwhatever",
290*e1fe3e4aSElliott Hughes                },
291*e1fe3e4aSElliott Hughes            ),
292*e1fe3e4aSElliott Hughes            InstanceDescriptor(
293*e1fe3e4aSElliott Hughes                filename="instances/instanceTest2.ufo",
294*e1fe3e4aSElliott Hughes                path=posix(str((datadir / "instances/instanceTest2.ufo").resolve())),
295*e1fe3e4aSElliott Hughes                name="instance.ufo2",
296*e1fe3e4aSElliott Hughes                designLocation={"Weight": 500.0, "Width": (400.0, 300.0)},
297*e1fe3e4aSElliott Hughes                familyName="InstanceFamilyName",
298*e1fe3e4aSElliott Hughes                styleName="InstanceStyleName",
299*e1fe3e4aSElliott Hughes                postScriptFontName="InstancePostscriptName",
300*e1fe3e4aSElliott Hughes                styleMapFamilyName="InstanceStyleMapFamilyName",
301*e1fe3e4aSElliott Hughes                styleMapStyleName="InstanceStyleMapStyleName",
302*e1fe3e4aSElliott Hughes                glyphs={
303*e1fe3e4aSElliott Hughes                    "arrow": {
304*e1fe3e4aSElliott Hughes                        "unicodes": [101, 201, 301],
305*e1fe3e4aSElliott Hughes                        "note": "A note about this glyph",
306*e1fe3e4aSElliott Hughes                        "instanceLocation": {"Weight": 120.0, "Width": 100.0},
307*e1fe3e4aSElliott Hughes                        "masters": [
308*e1fe3e4aSElliott Hughes                            {
309*e1fe3e4aSElliott Hughes                                "font": "master.ufo1",
310*e1fe3e4aSElliott Hughes                                "location": {"Weight": 20.0, "Width": 20.0},
311*e1fe3e4aSElliott Hughes                                "glyphName": "BB",
312*e1fe3e4aSElliott Hughes                            },
313*e1fe3e4aSElliott Hughes                            {
314*e1fe3e4aSElliott Hughes                                "font": "master.ufo2",
315*e1fe3e4aSElliott Hughes                                "location": {"Weight": 900.0, "Width": 900.0},
316*e1fe3e4aSElliott Hughes                                "glyphName": "CC",
317*e1fe3e4aSElliott Hughes                            },
318*e1fe3e4aSElliott Hughes                        ],
319*e1fe3e4aSElliott Hughes                    },
320*e1fe3e4aSElliott Hughes                    "arrow2": {},
321*e1fe3e4aSElliott Hughes                },
322*e1fe3e4aSElliott Hughes            ),
323*e1fe3e4aSElliott Hughes            InstanceDescriptor(
324*e1fe3e4aSElliott Hughes                locationLabel="Some Style",
325*e1fe3e4aSElliott Hughes            ),
326*e1fe3e4aSElliott Hughes            InstanceDescriptor(
327*e1fe3e4aSElliott Hughes                designLocation={"Weight": 600.0, "Width": (401.0, 420.0)},
328*e1fe3e4aSElliott Hughes            ),
329*e1fe3e4aSElliott Hughes            InstanceDescriptor(
330*e1fe3e4aSElliott Hughes                designLocation={"Weight": 10.0, "Italic": 0.0},
331*e1fe3e4aSElliott Hughes                userLocation={"Width": 100.0},
332*e1fe3e4aSElliott Hughes            ),
333*e1fe3e4aSElliott Hughes            InstanceDescriptor(
334*e1fe3e4aSElliott Hughes                userLocation={"Weight": 300.0, "Width": 130.0, "Italic": 1.0},
335*e1fe3e4aSElliott Hughes            ),
336*e1fe3e4aSElliott Hughes        ],
337*e1fe3e4aSElliott Hughes    )
338*e1fe3e4aSElliott Hughes
339*e1fe3e4aSElliott Hughes
340*e1fe3e4aSElliott Hughesdef test_read_v5_document_decovar(datadir):
341*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument.fromfile(datadir / "test_v5_decovar.designspace")
342*e1fe3e4aSElliott Hughes
343*e1fe3e4aSElliott Hughes    assert not doc.variableFonts
344*e1fe3e4aSElliott Hughes
345*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
346*e1fe3e4aSElliott Hughes        doc.axes,
347*e1fe3e4aSElliott Hughes        [
348*e1fe3e4aSElliott Hughes            AxisDescriptor(
349*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Inline", tag="BLDA"
350*e1fe3e4aSElliott Hughes            ),
351*e1fe3e4aSElliott Hughes            AxisDescriptor(
352*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Shearded", tag="TRMD"
353*e1fe3e4aSElliott Hughes            ),
354*e1fe3e4aSElliott Hughes            AxisDescriptor(
355*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Rounded Slab", tag="TRMC"
356*e1fe3e4aSElliott Hughes            ),
357*e1fe3e4aSElliott Hughes            AxisDescriptor(
358*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Stripes", tag="SKLD"
359*e1fe3e4aSElliott Hughes            ),
360*e1fe3e4aSElliott Hughes            AxisDescriptor(
361*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Worm Terminal", tag="TRML"
362*e1fe3e4aSElliott Hughes            ),
363*e1fe3e4aSElliott Hughes            AxisDescriptor(
364*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Inline Skeleton", tag="SKLA"
365*e1fe3e4aSElliott Hughes            ),
366*e1fe3e4aSElliott Hughes            AxisDescriptor(
367*e1fe3e4aSElliott Hughes                default=0,
368*e1fe3e4aSElliott Hughes                maximum=1000,
369*e1fe3e4aSElliott Hughes                minimum=0,
370*e1fe3e4aSElliott Hughes                name="Open Inline Terminal",
371*e1fe3e4aSElliott Hughes                tag="TRMF",
372*e1fe3e4aSElliott Hughes            ),
373*e1fe3e4aSElliott Hughes            AxisDescriptor(
374*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Inline Terminal", tag="TRMK"
375*e1fe3e4aSElliott Hughes            ),
376*e1fe3e4aSElliott Hughes            AxisDescriptor(default=0, maximum=1000, minimum=0, name="Worm", tag="BLDB"),
377*e1fe3e4aSElliott Hughes            AxisDescriptor(
378*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Weight", tag="WMX2"
379*e1fe3e4aSElliott Hughes            ),
380*e1fe3e4aSElliott Hughes            AxisDescriptor(
381*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Flared", tag="TRMB"
382*e1fe3e4aSElliott Hughes            ),
383*e1fe3e4aSElliott Hughes            AxisDescriptor(
384*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Rounded", tag="TRMA"
385*e1fe3e4aSElliott Hughes            ),
386*e1fe3e4aSElliott Hughes            AxisDescriptor(
387*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Worm Skeleton", tag="SKLB"
388*e1fe3e4aSElliott Hughes            ),
389*e1fe3e4aSElliott Hughes            AxisDescriptor(default=0, maximum=1000, minimum=0, name="Slab", tag="TRMG"),
390*e1fe3e4aSElliott Hughes            AxisDescriptor(
391*e1fe3e4aSElliott Hughes                default=0, maximum=1000, minimum=0, name="Bifurcated", tag="TRME"
392*e1fe3e4aSElliott Hughes            ),
393*e1fe3e4aSElliott Hughes        ],
394*e1fe3e4aSElliott Hughes    )
395*e1fe3e4aSElliott Hughes
396*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
397*e1fe3e4aSElliott Hughes        doc.locationLabels,
398*e1fe3e4aSElliott Hughes        [
399*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Default", elidable=True, userLocation={}),
400*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
401*e1fe3e4aSElliott Hughes                name="Open", userLocation={"Inline": 1000}, labelNames={"de": "Offen"}
402*e1fe3e4aSElliott Hughes            ),
403*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Worm", userLocation={"Worm": 1000}),
404*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
405*e1fe3e4aSElliott Hughes                name="Checkered", userLocation={"Inline Skeleton": 1000}
406*e1fe3e4aSElliott Hughes            ),
407*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
408*e1fe3e4aSElliott Hughes                name="Checkered Reverse", userLocation={"Inline Terminal": 1000}
409*e1fe3e4aSElliott Hughes            ),
410*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Striped", userLocation={"Stripes": 500}),
411*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Rounded", userLocation={"Rounded": 1000}),
412*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Flared", userLocation={"Flared": 1000}),
413*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
414*e1fe3e4aSElliott Hughes                name="Flared Open",
415*e1fe3e4aSElliott Hughes                userLocation={"Inline Skeleton": 1000, "Flared": 1000},
416*e1fe3e4aSElliott Hughes            ),
417*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
418*e1fe3e4aSElliott Hughes                name="Rounded Slab", userLocation={"Rounded Slab": 1000}
419*e1fe3e4aSElliott Hughes            ),
420*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Sheared", userLocation={"Shearded": 1000}),
421*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
422*e1fe3e4aSElliott Hughes                name="Bifurcated", userLocation={"Bifurcated": 1000}
423*e1fe3e4aSElliott Hughes            ),
424*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
425*e1fe3e4aSElliott Hughes                name="Inline",
426*e1fe3e4aSElliott Hughes                userLocation={"Inline Skeleton": 500, "Open Inline Terminal": 500},
427*e1fe3e4aSElliott Hughes            ),
428*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Slab", userLocation={"Slab": 1000}),
429*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(name="Contrast", userLocation={"Weight": 1000}),
430*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
431*e1fe3e4aSElliott Hughes                name="Fancy",
432*e1fe3e4aSElliott Hughes                userLocation={"Inline Skeleton": 1000, "Flared": 1000, "Weight": 1000},
433*e1fe3e4aSElliott Hughes            ),
434*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
435*e1fe3e4aSElliott Hughes                name="Mayhem",
436*e1fe3e4aSElliott Hughes                userLocation={
437*e1fe3e4aSElliott Hughes                    "Inline Skeleton": 1000,
438*e1fe3e4aSElliott Hughes                    "Worm Skeleton": 1000,
439*e1fe3e4aSElliott Hughes                    "Rounded": 500,
440*e1fe3e4aSElliott Hughes                    "Flared": 500,
441*e1fe3e4aSElliott Hughes                    "Rounded Slab": 750,
442*e1fe3e4aSElliott Hughes                    "Bifurcated": 500,
443*e1fe3e4aSElliott Hughes                    "Open Inline Terminal": 250,
444*e1fe3e4aSElliott Hughes                    "Slab": 750,
445*e1fe3e4aSElliott Hughes                    "Inline Terminal": 250,
446*e1fe3e4aSElliott Hughes                    "Worm Terminal": 250,
447*e1fe3e4aSElliott Hughes                    "Weight": 750,
448*e1fe3e4aSElliott Hughes                    "Worm": 1000,
449*e1fe3e4aSElliott Hughes                },
450*e1fe3e4aSElliott Hughes            ),
451*e1fe3e4aSElliott Hughes        ],
452*e1fe3e4aSElliott Hughes    )
453*e1fe3e4aSElliott Hughes
454*e1fe3e4aSElliott Hughes    assert [i.locationLabel for i in doc.instances] == [
455*e1fe3e4aSElliott Hughes        "Default",
456*e1fe3e4aSElliott Hughes        "Open",
457*e1fe3e4aSElliott Hughes        "Worm",
458*e1fe3e4aSElliott Hughes        "Checkered",
459*e1fe3e4aSElliott Hughes        "Checkered Reverse",
460*e1fe3e4aSElliott Hughes        "Striped",
461*e1fe3e4aSElliott Hughes        "Rounded",
462*e1fe3e4aSElliott Hughes        "Flared",
463*e1fe3e4aSElliott Hughes        "Flared Open",
464*e1fe3e4aSElliott Hughes        "Rounded Slab",
465*e1fe3e4aSElliott Hughes        "Sheared",
466*e1fe3e4aSElliott Hughes        "Bifurcated",
467*e1fe3e4aSElliott Hughes        "Inline",
468*e1fe3e4aSElliott Hughes        "Slab",
469*e1fe3e4aSElliott Hughes        "Contrast",
470*e1fe3e4aSElliott Hughes        "Fancy",
471*e1fe3e4aSElliott Hughes        "Mayhem",
472*e1fe3e4aSElliott Hughes    ]
473*e1fe3e4aSElliott Hughes
474*e1fe3e4aSElliott Hughes
475*e1fe3e4aSElliott Hughesdef test_read_v5_document_discrete(datadir):
476*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument.fromfile(datadir / "test_v5_discrete.designspace")
477*e1fe3e4aSElliott Hughes
478*e1fe3e4aSElliott Hughes    assert not doc.locationLabels
479*e1fe3e4aSElliott Hughes    assert not doc.variableFonts
480*e1fe3e4aSElliott Hughes
481*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
482*e1fe3e4aSElliott Hughes        doc.axes,
483*e1fe3e4aSElliott Hughes        [
484*e1fe3e4aSElliott Hughes            DiscreteAxisDescriptor(
485*e1fe3e4aSElliott Hughes                default=400,
486*e1fe3e4aSElliott Hughes                values=[400, 700, 900],
487*e1fe3e4aSElliott Hughes                name="Weight",
488*e1fe3e4aSElliott Hughes                tag="wght",
489*e1fe3e4aSElliott Hughes                axisLabels=[
490*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
491*e1fe3e4aSElliott Hughes                        name="Regular",
492*e1fe3e4aSElliott Hughes                        userValue=400,
493*e1fe3e4aSElliott Hughes                        elidable=True,
494*e1fe3e4aSElliott Hughes                        linkedUserValue=700,
495*e1fe3e4aSElliott Hughes                    ),
496*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Bold", userValue=700),
497*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Black", userValue=900),
498*e1fe3e4aSElliott Hughes                ],
499*e1fe3e4aSElliott Hughes            ),
500*e1fe3e4aSElliott Hughes            DiscreteAxisDescriptor(
501*e1fe3e4aSElliott Hughes                default=100,
502*e1fe3e4aSElliott Hughes                values=[75, 100],
503*e1fe3e4aSElliott Hughes                name="Width",
504*e1fe3e4aSElliott Hughes                tag="wdth",
505*e1fe3e4aSElliott Hughes                axisLabels=[
506*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Narrow", userValue=75),
507*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Normal", userValue=100, elidable=True),
508*e1fe3e4aSElliott Hughes                ],
509*e1fe3e4aSElliott Hughes            ),
510*e1fe3e4aSElliott Hughes            DiscreteAxisDescriptor(
511*e1fe3e4aSElliott Hughes                default=0,
512*e1fe3e4aSElliott Hughes                values=[0, 1],
513*e1fe3e4aSElliott Hughes                name="Italic",
514*e1fe3e4aSElliott Hughes                tag="ital",
515*e1fe3e4aSElliott Hughes                axisLabels=[
516*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
517*e1fe3e4aSElliott Hughes                        name="Roman", userValue=0, elidable=True, linkedUserValue=1
518*e1fe3e4aSElliott Hughes                    ),
519*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Italic", userValue=1),
520*e1fe3e4aSElliott Hughes                ],
521*e1fe3e4aSElliott Hughes            ),
522*e1fe3e4aSElliott Hughes        ],
523*e1fe3e4aSElliott Hughes    )
524*e1fe3e4aSElliott Hughes
525*e1fe3e4aSElliott Hughes
526*e1fe3e4aSElliott Hughesdef test_read_v5_document_aktiv(datadir):
527*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument.fromfile(datadir / "test_v5_aktiv.designspace")
528*e1fe3e4aSElliott Hughes
529*e1fe3e4aSElliott Hughes    assert not doc.locationLabels
530*e1fe3e4aSElliott Hughes
531*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
532*e1fe3e4aSElliott Hughes        doc.axes,
533*e1fe3e4aSElliott Hughes        [
534*e1fe3e4aSElliott Hughes            AxisDescriptor(
535*e1fe3e4aSElliott Hughes                tag="wght",
536*e1fe3e4aSElliott Hughes                name="Weight",
537*e1fe3e4aSElliott Hughes                minimum=100,
538*e1fe3e4aSElliott Hughes                default=400,
539*e1fe3e4aSElliott Hughes                maximum=900,
540*e1fe3e4aSElliott Hughes                map=[
541*e1fe3e4aSElliott Hughes                    (100, 22),
542*e1fe3e4aSElliott Hughes                    (200, 38),
543*e1fe3e4aSElliott Hughes                    (300, 57),
544*e1fe3e4aSElliott Hughes                    (400, 84),
545*e1fe3e4aSElliott Hughes                    (500, 98),
546*e1fe3e4aSElliott Hughes                    (600, 115),
547*e1fe3e4aSElliott Hughes                    (700, 133),
548*e1fe3e4aSElliott Hughes                    (800, 158),
549*e1fe3e4aSElliott Hughes                    (900, 185),
550*e1fe3e4aSElliott Hughes                ],
551*e1fe3e4aSElliott Hughes                axisOrdering=1,
552*e1fe3e4aSElliott Hughes                axisLabels=[
553*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Hair", userValue=100),
554*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=200, name="Thin"),
555*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=300, name="Light"),
556*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
557*e1fe3e4aSElliott Hughes                        userValue=400,
558*e1fe3e4aSElliott Hughes                        name="Regular",
559*e1fe3e4aSElliott Hughes                        elidable=True,
560*e1fe3e4aSElliott Hughes                        linkedUserValue=700,
561*e1fe3e4aSElliott Hughes                    ),
562*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=500, name="Medium"),
563*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=600, name="SemiBold"),
564*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=700, name="Bold"),
565*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=800, name="XBold"),
566*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(userValue=900, name="Black"),
567*e1fe3e4aSElliott Hughes                ],
568*e1fe3e4aSElliott Hughes            ),
569*e1fe3e4aSElliott Hughes            AxisDescriptor(
570*e1fe3e4aSElliott Hughes                tag="wdth",
571*e1fe3e4aSElliott Hughes                name="Width",
572*e1fe3e4aSElliott Hughes                minimum=75,
573*e1fe3e4aSElliott Hughes                default=100,
574*e1fe3e4aSElliott Hughes                maximum=125,
575*e1fe3e4aSElliott Hughes                axisOrdering=0,
576*e1fe3e4aSElliott Hughes                axisLabels=[
577*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Cd", userValue=75),
578*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Normal", elidable=True, userValue=100),
579*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Ex", userValue=125),
580*e1fe3e4aSElliott Hughes                ],
581*e1fe3e4aSElliott Hughes            ),
582*e1fe3e4aSElliott Hughes            AxisDescriptor(
583*e1fe3e4aSElliott Hughes                tag="ital",
584*e1fe3e4aSElliott Hughes                name="Italic",
585*e1fe3e4aSElliott Hughes                minimum=0,
586*e1fe3e4aSElliott Hughes                default=0,
587*e1fe3e4aSElliott Hughes                maximum=1,
588*e1fe3e4aSElliott Hughes                axisOrdering=2,
589*e1fe3e4aSElliott Hughes                axisLabels=[
590*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
591*e1fe3e4aSElliott Hughes                        name="Upright", userValue=0, elidable=True, linkedUserValue=1
592*e1fe3e4aSElliott Hughes                    ),
593*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(name="Italic", userValue=1),
594*e1fe3e4aSElliott Hughes                ],
595*e1fe3e4aSElliott Hughes            ),
596*e1fe3e4aSElliott Hughes        ],
597*e1fe3e4aSElliott Hughes    )
598*e1fe3e4aSElliott Hughes
599*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
600*e1fe3e4aSElliott Hughes        doc.variableFonts,
601*e1fe3e4aSElliott Hughes        [
602*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
603*e1fe3e4aSElliott Hughes                name="AktivGroteskVF_WghtWdthItal",
604*e1fe3e4aSElliott Hughes                axisSubsets=[
605*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
606*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Width"),
607*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Italic"),
608*e1fe3e4aSElliott Hughes                ],
609*e1fe3e4aSElliott Hughes            ),
610*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
611*e1fe3e4aSElliott Hughes                name="AktivGroteskVF_WghtWdth",
612*e1fe3e4aSElliott Hughes                axisSubsets=[
613*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
614*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Width"),
615*e1fe3e4aSElliott Hughes                ],
616*e1fe3e4aSElliott Hughes            ),
617*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
618*e1fe3e4aSElliott Hughes                name="AktivGroteskVF_Wght",
619*e1fe3e4aSElliott Hughes                axisSubsets=[
620*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
621*e1fe3e4aSElliott Hughes                ],
622*e1fe3e4aSElliott Hughes            ),
623*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
624*e1fe3e4aSElliott Hughes                name="AktivGroteskVF_Italics_WghtWdth",
625*e1fe3e4aSElliott Hughes                axisSubsets=[
626*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
627*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Width"),
628*e1fe3e4aSElliott Hughes                    ValueAxisSubsetDescriptor(name="Italic", userValue=1),
629*e1fe3e4aSElliott Hughes                ],
630*e1fe3e4aSElliott Hughes            ),
631*e1fe3e4aSElliott Hughes            VariableFontDescriptor(
632*e1fe3e4aSElliott Hughes                name="AktivGroteskVF_Italics_Wght",
633*e1fe3e4aSElliott Hughes                axisSubsets=[
634*e1fe3e4aSElliott Hughes                    RangeAxisSubsetDescriptor(name="Weight"),
635*e1fe3e4aSElliott Hughes                    ValueAxisSubsetDescriptor(name="Italic", userValue=1),
636*e1fe3e4aSElliott Hughes                ],
637*e1fe3e4aSElliott Hughes            ),
638*e1fe3e4aSElliott Hughes        ],
639*e1fe3e4aSElliott Hughes    )
640*e1fe3e4aSElliott Hughes
641*e1fe3e4aSElliott Hughes
642*e1fe3e4aSElliott Hughes@pytest.fixture
643*e1fe3e4aSElliott Hughesdef map_doc():
644*e1fe3e4aSElliott Hughes    """Generate a document with a few axes to test the mapping functions"""
645*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument()
646*e1fe3e4aSElliott Hughes    doc.addAxis(
647*e1fe3e4aSElliott Hughes        AxisDescriptor(
648*e1fe3e4aSElliott Hughes            tag="wght",
649*e1fe3e4aSElliott Hughes            name="Weight",
650*e1fe3e4aSElliott Hughes            minimum=100,
651*e1fe3e4aSElliott Hughes            maximum=900,
652*e1fe3e4aSElliott Hughes            default=100,
653*e1fe3e4aSElliott Hughes            map=[(100, 10), (900, 90)],
654*e1fe3e4aSElliott Hughes        )
655*e1fe3e4aSElliott Hughes    )
656*e1fe3e4aSElliott Hughes    doc.addAxis(
657*e1fe3e4aSElliott Hughes        AxisDescriptor(
658*e1fe3e4aSElliott Hughes            tag="wdth",
659*e1fe3e4aSElliott Hughes            name="Width",
660*e1fe3e4aSElliott Hughes            minimum=75,
661*e1fe3e4aSElliott Hughes            maximum=200,
662*e1fe3e4aSElliott Hughes            default=100,
663*e1fe3e4aSElliott Hughes            map=[(75, 7500), (100, 10000), (200, 20000)],
664*e1fe3e4aSElliott Hughes        )
665*e1fe3e4aSElliott Hughes    )
666*e1fe3e4aSElliott Hughes    doc.addAxis(
667*e1fe3e4aSElliott Hughes        AxisDescriptor(tag="CUST", name="Custom", minimum=1, maximum=2, default=1.5)
668*e1fe3e4aSElliott Hughes    )
669*e1fe3e4aSElliott Hughes    doc.addLocationLabel(
670*e1fe3e4aSElliott Hughes        LocationLabelDescriptor(
671*e1fe3e4aSElliott Hughes            name="Wonky", userLocation={"Weight": 800, "Custom": 1.2}
672*e1fe3e4aSElliott Hughes        )
673*e1fe3e4aSElliott Hughes    )
674*e1fe3e4aSElliott Hughes    return doc
675*e1fe3e4aSElliott Hughes
676*e1fe3e4aSElliott Hughes
677*e1fe3e4aSElliott Hughesdef test_doc_location_map_forward(map_doc: DesignSpaceDocument):
678*e1fe3e4aSElliott Hughes    assert map_doc.map_forward({"Weight": 400, "Width": 150, "Custom": 2}) == {
679*e1fe3e4aSElliott Hughes        "Weight": 40,
680*e1fe3e4aSElliott Hughes        "Width": 15000,
681*e1fe3e4aSElliott Hughes        "Custom": 2,
682*e1fe3e4aSElliott Hughes    }, "The mappings should be used to compute the design locations"
683*e1fe3e4aSElliott Hughes    assert map_doc.map_forward({"Weight": 400}) == {
684*e1fe3e4aSElliott Hughes        "Weight": 40,
685*e1fe3e4aSElliott Hughes        "Width": 10000,
686*e1fe3e4aSElliott Hughes        "Custom": 1.5,
687*e1fe3e4aSElliott Hughes    }, "Missing user locations should be assumed equal to the axis's default"
688*e1fe3e4aSElliott Hughes
689*e1fe3e4aSElliott Hughes
690*e1fe3e4aSElliott Hughesdef test_doc_location_map_backward(map_doc: DesignSpaceDocument):
691*e1fe3e4aSElliott Hughes    assert map_doc.map_backward({"Weight": 40, "Width": 15000, "Custom": 2}) == {
692*e1fe3e4aSElliott Hughes        "Weight": 400,
693*e1fe3e4aSElliott Hughes        "Width": 150,
694*e1fe3e4aSElliott Hughes        "Custom": 2,
695*e1fe3e4aSElliott Hughes    }, "The mappings should be used to compute the user locations"
696*e1fe3e4aSElliott Hughes    assert map_doc.map_backward({"Weight": 40}) == {
697*e1fe3e4aSElliott Hughes        "Weight": 400,
698*e1fe3e4aSElliott Hughes        "Width": 100,
699*e1fe3e4aSElliott Hughes        "Custom": 1.5,
700*e1fe3e4aSElliott Hughes    }, "Missing design locations should be assumed equal to the axis's default"
701*e1fe3e4aSElliott Hughes    assert map_doc.map_backward(
702*e1fe3e4aSElliott Hughes        {"Weight": (40, 50), "Width": (15000, 100000), "Custom": (2, 1.5)}
703*e1fe3e4aSElliott Hughes    ) == {
704*e1fe3e4aSElliott Hughes        "Weight": 400,
705*e1fe3e4aSElliott Hughes        "Width": 150,
706*e1fe3e4aSElliott Hughes        "Custom": 2,
707*e1fe3e4aSElliott Hughes    }, "Only the xvalue of anisotropic locations is used"
708*e1fe3e4aSElliott Hughes
709*e1fe3e4aSElliott Hughes
710*e1fe3e4aSElliott Hughesdef test_instance_location_from_label(map_doc):
711*e1fe3e4aSElliott Hughes    inst = InstanceDescriptor(locationLabel="Wonky")
712*e1fe3e4aSElliott Hughes    assert inst.getFullUserLocation(map_doc) == {
713*e1fe3e4aSElliott Hughes        "Weight": 800,
714*e1fe3e4aSElliott Hughes        "Width": 100,
715*e1fe3e4aSElliott Hughes        "Custom": 1.2,
716*e1fe3e4aSElliott Hughes    }, "an instance with a locationLabel uses the user location from that label, empty values on the label use axis defaults"
717*e1fe3e4aSElliott Hughes    assert inst.getFullDesignLocation(map_doc) == {
718*e1fe3e4aSElliott Hughes        "Weight": 80,
719*e1fe3e4aSElliott Hughes        "Width": 10000,
720*e1fe3e4aSElliott Hughes        "Custom": 1.2,
721*e1fe3e4aSElliott Hughes    }, "an instance with a locationLabel computes the design location from that label, empty values on the label use axis defaults"
722*e1fe3e4aSElliott Hughes
723*e1fe3e4aSElliott Hughes    inst = InstanceDescriptor(locationLabel="Wonky", userLocation={"Width": 200})
724*e1fe3e4aSElliott Hughes    assert inst.getFullUserLocation(map_doc) == {
725*e1fe3e4aSElliott Hughes        "Weight": 800,
726*e1fe3e4aSElliott Hughes        "Width": 100,
727*e1fe3e4aSElliott Hughes        "Custom": 1.2,
728*e1fe3e4aSElliott Hughes    }, "an instance with a locationLabel uses the user location from that label, other location values are ignored"
729*e1fe3e4aSElliott Hughes    assert inst.getFullDesignLocation(map_doc) == {
730*e1fe3e4aSElliott Hughes        "Weight": 80,
731*e1fe3e4aSElliott Hughes        "Width": 10000,
732*e1fe3e4aSElliott Hughes        "Custom": 1.2,
733*e1fe3e4aSElliott Hughes    }, "an instance with a locationLabel computes the design location from that label, other location values are ignored"
734*e1fe3e4aSElliott Hughes
735*e1fe3e4aSElliott Hughes
736*e1fe3e4aSElliott Hughesdef test_instance_location_no_data(map_doc):
737*e1fe3e4aSElliott Hughes    inst = InstanceDescriptor()
738*e1fe3e4aSElliott Hughes    assert inst.getFullUserLocation(map_doc) == {
739*e1fe3e4aSElliott Hughes        "Weight": 100,
740*e1fe3e4aSElliott Hughes        "Width": 100,
741*e1fe3e4aSElliott Hughes        "Custom": 1.5,
742*e1fe3e4aSElliott Hughes    }, "an instance without any location data has the default user location"
743*e1fe3e4aSElliott Hughes    assert inst.getFullDesignLocation(map_doc) == {
744*e1fe3e4aSElliott Hughes        "Weight": 10,
745*e1fe3e4aSElliott Hughes        "Width": 10000,
746*e1fe3e4aSElliott Hughes        "Custom": 1.5,
747*e1fe3e4aSElliott Hughes    }, "an instance without any location data has the default design location"
748*e1fe3e4aSElliott Hughes
749*e1fe3e4aSElliott Hughes
750*e1fe3e4aSElliott Hughesdef test_instance_location_design_first(map_doc):
751*e1fe3e4aSElliott Hughes    inst = InstanceDescriptor(
752*e1fe3e4aSElliott Hughes        designLocation={"Weight": (60, 61), "Width": 11000, "Custom": 1.2},
753*e1fe3e4aSElliott Hughes        userLocation={"Weight": 700, "Width": 180, "Custom": 1.4},
754*e1fe3e4aSElliott Hughes    )
755*e1fe3e4aSElliott Hughes    assert inst.getFullUserLocation(map_doc) == {
756*e1fe3e4aSElliott Hughes        "Weight": 600,
757*e1fe3e4aSElliott Hughes        "Width": 110,
758*e1fe3e4aSElliott Hughes        "Custom": 1.2,
759*e1fe3e4aSElliott Hughes    }, "when both design and user location data are provided, design wins"
760*e1fe3e4aSElliott Hughes    assert inst.getFullDesignLocation(map_doc) == {
761*e1fe3e4aSElliott Hughes        "Weight": (60, 61),
762*e1fe3e4aSElliott Hughes        "Width": 11000,
763*e1fe3e4aSElliott Hughes        "Custom": 1.2,
764*e1fe3e4aSElliott Hughes    }, "when both design and user location data are provided, design wins (incl. anisotropy)"
765*e1fe3e4aSElliott Hughes
766*e1fe3e4aSElliott Hughes
767*e1fe3e4aSElliott Hughesdef test_instance_location_mix(map_doc):
768*e1fe3e4aSElliott Hughes    inst = InstanceDescriptor(
769*e1fe3e4aSElliott Hughes        designLocation={"Weight": (60, 61)},
770*e1fe3e4aSElliott Hughes        userLocation={"Width": 180},
771*e1fe3e4aSElliott Hughes    )
772*e1fe3e4aSElliott Hughes    assert inst.getFullUserLocation(map_doc) == {
773*e1fe3e4aSElliott Hughes        "Weight": 600,
774*e1fe3e4aSElliott Hughes        "Width": 180,
775*e1fe3e4aSElliott Hughes        "Custom": 1.5,
776*e1fe3e4aSElliott Hughes    }, "instance location is a mix of design and user locations"
777*e1fe3e4aSElliott Hughes    assert inst.getFullDesignLocation(map_doc) == {
778*e1fe3e4aSElliott Hughes        "Weight": (60, 61),
779*e1fe3e4aSElliott Hughes        "Width": 18000,
780*e1fe3e4aSElliott Hughes        "Custom": 1.5,
781*e1fe3e4aSElliott Hughes    }, "instance location is a mix of design and user location"
782*e1fe3e4aSElliott Hughes
783*e1fe3e4aSElliott Hughes
784*e1fe3e4aSElliott Hughes@pytest.mark.parametrize(
785*e1fe3e4aSElliott Hughes    "filename",
786*e1fe3e4aSElliott Hughes    [
787*e1fe3e4aSElliott Hughes        "test_v4_original.designspace",
788*e1fe3e4aSElliott Hughes        "test_v5_original.designspace",
789*e1fe3e4aSElliott Hughes        "test_v5_aktiv.designspace",
790*e1fe3e4aSElliott Hughes        "test_v5_decovar.designspace",
791*e1fe3e4aSElliott Hughes        "test_v5_discrete.designspace",
792*e1fe3e4aSElliott Hughes        "test_v5_sourceserif.designspace",
793*e1fe3e4aSElliott Hughes        "test_v5.designspace",
794*e1fe3e4aSElliott Hughes    ],
795*e1fe3e4aSElliott Hughes)
796*e1fe3e4aSElliott Hughesdef test_roundtrip(tmpdir, datadir, filename):
797*e1fe3e4aSElliott Hughes    test_file = datadir / filename
798*e1fe3e4aSElliott Hughes    output_path = tmpdir / filename
799*e1fe3e4aSElliott Hughes    # Move the file to the tmpdir so that the filenames stay the same
800*e1fe3e4aSElliott Hughes    # (they're relative to the file's path)
801*e1fe3e4aSElliott Hughes    shutil.copy(test_file, output_path)
802*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument.fromfile(output_path)
803*e1fe3e4aSElliott Hughes    doc.write(output_path)
804*e1fe3e4aSElliott Hughes    # The input XML has comments and empty lines for documentation purposes
805*e1fe3e4aSElliott Hughes    xml = test_file.read_text(encoding="utf-8")
806*e1fe3e4aSElliott Hughes    xml = re.sub(
807*e1fe3e4aSElliott Hughes        r"<!-- ROUNDTRIP_TEST_REMOVE_ME_BEGIN -->(.|\n)*?<!-- ROUNDTRIP_TEST_REMOVE_ME_END -->",
808*e1fe3e4aSElliott Hughes        "",
809*e1fe3e4aSElliott Hughes        xml,
810*e1fe3e4aSElliott Hughes    )
811*e1fe3e4aSElliott Hughes    xml = re.sub(r"<!--(.|\n)*?-->", "", xml)
812*e1fe3e4aSElliott Hughes    xml = re.sub(r"\s*\n+", "\n", xml)
813*e1fe3e4aSElliott Hughes    assert output_path.read_text(encoding="utf-8") == xml
814*e1fe3e4aSElliott Hughes
815*e1fe3e4aSElliott Hughes
816*e1fe3e4aSElliott Hughesdef test_using_v5_features_upgrades_format(tmpdir, datadir):
817*e1fe3e4aSElliott Hughes    test_file = datadir / "test_v4_original.designspace"
818*e1fe3e4aSElliott Hughes    output_4_path = tmpdir / "test_v4.designspace"
819*e1fe3e4aSElliott Hughes    output_5_path = tmpdir / "test_v5.designspace"
820*e1fe3e4aSElliott Hughes    shutil.copy(test_file, output_4_path)
821*e1fe3e4aSElliott Hughes    doc = DesignSpaceDocument.fromfile(output_4_path)
822*e1fe3e4aSElliott Hughes    doc.write(output_4_path)
823*e1fe3e4aSElliott Hughes    assert 'format="4.1"' in output_4_path.read_text(encoding="utf-8")
824*e1fe3e4aSElliott Hughes    doc.addVariableFont(VariableFontDescriptor(name="TestVF"))
825*e1fe3e4aSElliott Hughes    doc.write(output_5_path)
826*e1fe3e4aSElliott Hughes    assert 'format="5.0"' in output_5_path.read_text(encoding="utf-8")
827*e1fe3e4aSElliott Hughes
828*e1fe3e4aSElliott Hughes
829*e1fe3e4aSElliott Hughesdef test_addAxisDescriptor_discrete():
830*e1fe3e4aSElliott Hughes    ds = DesignSpaceDocument()
831*e1fe3e4aSElliott Hughes
832*e1fe3e4aSElliott Hughes    axis = ds.addAxisDescriptor(
833*e1fe3e4aSElliott Hughes        name="Italic",
834*e1fe3e4aSElliott Hughes        tag="ital",
835*e1fe3e4aSElliott Hughes        values=[0, 1],
836*e1fe3e4aSElliott Hughes        default=0,
837*e1fe3e4aSElliott Hughes        hidden=True,
838*e1fe3e4aSElliott Hughes        map=[(0, -12), (1, 0)],
839*e1fe3e4aSElliott Hughes        axisOrdering=3,
840*e1fe3e4aSElliott Hughes        axisLabels=[
841*e1fe3e4aSElliott Hughes            AxisLabelDescriptor(
842*e1fe3e4aSElliott Hughes                name="Roman",
843*e1fe3e4aSElliott Hughes                userValue=0,
844*e1fe3e4aSElliott Hughes                elidable=True,
845*e1fe3e4aSElliott Hughes                olderSibling=True,
846*e1fe3e4aSElliott Hughes                linkedUserValue=1,
847*e1fe3e4aSElliott Hughes                labelNames={"fr": "Romain"},
848*e1fe3e4aSElliott Hughes            )
849*e1fe3e4aSElliott Hughes        ],
850*e1fe3e4aSElliott Hughes    )
851*e1fe3e4aSElliott Hughes
852*e1fe3e4aSElliott Hughes    assert ds.axes[0] is axis
853*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
854*e1fe3e4aSElliott Hughes        [axis],
855*e1fe3e4aSElliott Hughes        [
856*e1fe3e4aSElliott Hughes            DiscreteAxisDescriptor(
857*e1fe3e4aSElliott Hughes                tag="ital",
858*e1fe3e4aSElliott Hughes                name="Italic",
859*e1fe3e4aSElliott Hughes                values=[0, 1],
860*e1fe3e4aSElliott Hughes                default=0,
861*e1fe3e4aSElliott Hughes                hidden=True,
862*e1fe3e4aSElliott Hughes                map=[(0, -12), (1, 0)],
863*e1fe3e4aSElliott Hughes                axisOrdering=3,
864*e1fe3e4aSElliott Hughes                axisLabels=[
865*e1fe3e4aSElliott Hughes                    AxisLabelDescriptor(
866*e1fe3e4aSElliott Hughes                        name="Roman",
867*e1fe3e4aSElliott Hughes                        userValue=0,
868*e1fe3e4aSElliott Hughes                        elidable=True,
869*e1fe3e4aSElliott Hughes                        olderSibling=True,
870*e1fe3e4aSElliott Hughes                        linkedUserValue=1,
871*e1fe3e4aSElliott Hughes                        labelNames={"fr": "Romain"},
872*e1fe3e4aSElliott Hughes                    )
873*e1fe3e4aSElliott Hughes                ],
874*e1fe3e4aSElliott Hughes            )
875*e1fe3e4aSElliott Hughes        ],
876*e1fe3e4aSElliott Hughes    )
877*e1fe3e4aSElliott Hughes
878*e1fe3e4aSElliott Hughes
879*e1fe3e4aSElliott Hughesdef test_addLocationLabelDescriptor():
880*e1fe3e4aSElliott Hughes    ds = DesignSpaceDocument()
881*e1fe3e4aSElliott Hughes
882*e1fe3e4aSElliott Hughes    label = ds.addLocationLabelDescriptor(
883*e1fe3e4aSElliott Hughes        name="Somewhere",
884*e1fe3e4aSElliott Hughes        userLocation={},
885*e1fe3e4aSElliott Hughes        elidable=True,
886*e1fe3e4aSElliott Hughes        olderSibling=True,
887*e1fe3e4aSElliott Hughes        labelNames={"fr": "Quelque part"},
888*e1fe3e4aSElliott Hughes    )
889*e1fe3e4aSElliott Hughes
890*e1fe3e4aSElliott Hughes    assert ds.locationLabels[0] is label
891*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
892*e1fe3e4aSElliott Hughes        [label],
893*e1fe3e4aSElliott Hughes        [
894*e1fe3e4aSElliott Hughes            LocationLabelDescriptor(
895*e1fe3e4aSElliott Hughes                name="Somewhere",
896*e1fe3e4aSElliott Hughes                userLocation={},
897*e1fe3e4aSElliott Hughes                elidable=True,
898*e1fe3e4aSElliott Hughes                olderSibling=True,
899*e1fe3e4aSElliott Hughes                labelNames={"fr": "Quelque part"},
900*e1fe3e4aSElliott Hughes            )
901*e1fe3e4aSElliott Hughes        ],
902*e1fe3e4aSElliott Hughes    )
903*e1fe3e4aSElliott Hughes
904*e1fe3e4aSElliott Hughes
905*e1fe3e4aSElliott Hughesdef test_addVariableFontDescriptor():
906*e1fe3e4aSElliott Hughes    ds = DesignSpaceDocument()
907*e1fe3e4aSElliott Hughes
908*e1fe3e4aSElliott Hughes    vf = ds.addVariableFontDescriptor(name="TestVF", filename="TestVF.ttf")
909*e1fe3e4aSElliott Hughes
910*e1fe3e4aSElliott Hughes    assert ds.variableFonts[0] is vf
911*e1fe3e4aSElliott Hughes    assert_descriptors_equal(
912*e1fe3e4aSElliott Hughes        [vf], [VariableFontDescriptor(name="TestVF", filename="TestVF.ttf")]
913*e1fe3e4aSElliott Hughes    )
914