From d1ec8e69793fb3db3686eec5be2fd42491dd13fe Mon Sep 17 00:00:00 2001 From: Harry Dalton Date: Thu, 1 Sep 2022 13:41:44 +0100 Subject: [PATCH] Test that DS5 splitting code handles unbounded conditions gracefully Conditions with unbounded values have a "minimum" or "maximum" value of None. These tests check that: a) The public-facing split functions can receive None values without crashing; and b) That their internal helper functions correctly translate the None values to math.inf and -math.inf to express them. These tests are expected to fail, indicating where a fix is required. --- Tests/designspaceLib/split_test.py | 53 +++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/Tests/designspaceLib/split_test.py b/Tests/designspaceLib/split_test.py index 8708f7048..f0d4f9bcd 100644 --- a/Tests/designspaceLib/split_test.py +++ b/Tests/designspaceLib/split_test.py @@ -1,9 +1,16 @@ +import math import shutil from pathlib import Path import pytest from fontTools.designspaceLib import DesignSpaceDocument -from fontTools.designspaceLib.split import splitInterpolable, splitVariableFonts, convert5to4 +from fontTools.designspaceLib.split import ( + _conditionSetFrom, + convert5to4, + splitInterpolable, + splitVariableFonts, +) +from fontTools.designspaceLib.types import ConditionSet, Range from .fixtures import datadir @@ -148,3 +155,47 @@ def test_convert5to4(datadir, tmpdir, test_ds, expected_vfs): assert data_out.read_text(encoding="utf-8") == temp_out.read_text( encoding="utf-8" ) + + +@pytest.mark.parametrize( + ["unbounded_condition"], + [ + ({"name": "Weight", "minimum": 500, "maximum": None},), + ({"name": "Weight", "minimum": None, "maximum": 500},), + ], +) +def test_optional_min_max(unbounded_condition): + """Check that split functions can handle conditions that are partially + unbounded without tripping over the None values.""" + doc = DesignSpaceDocument() + + doc.addAxisDescriptor( + name="Weight", tag="wght", minimum=400, maximum=1000, default=400 + ) + + doc.addRuleDescriptor( + name="unbounded", + conditionSets=[[unbounded_condition]], + ) + + assert len(list(splitInterpolable(doc))) == 1 + assert len(list(splitVariableFonts(doc))) == 1 + + +@pytest.mark.parametrize( + ["condition", "expected_set"], + [ + ( + {"name": "axis", "minimum": 0.5, "maximum": None}, + {"axis": Range(minimum=0.5, maximum=math.inf)}, + ), + ( + {"name": "axis", "minimum": None, "maximum": 0.5}, + {"axis": Range(minimum=-math.inf, maximum=0.5)}, + ), + ], +) +def test_optional_min_max_internal(condition, expected_set: ConditionSet): + """Check that split's internal helper functions produce the correct output + for conditions that are partially unbounded.""" + assert _conditionSetFrom([condition]) == expected_set