diff --git a/src/textual/css/_style_properties.py b/src/textual/css/_style_properties.py index 12a76b202..8be05f045 100644 --- a/src/textual/css/_style_properties.py +++ b/src/textual/css/_style_properties.py @@ -115,12 +115,12 @@ class ScalarProperty: ): raise StyleValueError("'auto' not allowed here") - if new_value.unit != Unit.AUTO: - if new_value is not None and new_value.unit not in self.units: + if new_value is not None and new_value.unit != Unit.AUTO: + if new_value.unit not in self.units: raise StyleValueError( f"{self.name} units must be one of {friendly_list(get_symbols(self.units))}" ) - if new_value is not None and new_value.is_percent: + if new_value.is_percent: new_value = Scalar( float(new_value.value), self.percent_unit, Unit.WIDTH ) diff --git a/tests/css/test_styles.py b/tests/css/test_styles.py index 039d5745f..49e4545ad 100644 --- a/tests/css/test_styles.py +++ b/tests/css/test_styles.py @@ -1,11 +1,15 @@ +from decimal import Decimal + import pytest from rich.style import Style from textual.color import Color -from textual.css.errors import StyleTypeError +from textual.css.errors import StyleTypeError, StyleValueError +from textual.css.scalar import Scalar, Unit from textual.css.styles import Styles, RenderStyles from textual.dom import DOMNode +from textual.widget import Widget def test_styles_reset(): @@ -131,3 +135,53 @@ def test_opacity_set_invalid_type_error(): styles = RenderStyles(DOMNode(), Styles(), Styles()) with pytest.raises(StyleTypeError): styles.opacity = "invalid value" + + +@pytest.mark.parametrize( + "size_dimension_input,size_dimension_expected_output", + [ + # fmt: off + [None, None], + [1, Scalar(1, Unit.CELLS, Unit.WIDTH)], + [1.0, Scalar(1.0, Unit.CELLS, Unit.WIDTH)], + [1.2, Scalar(1.2, Unit.CELLS, Unit.WIDTH)], + [1.2e3, Scalar(1200.0, Unit.CELLS, Unit.WIDTH)], + ["20", Scalar(20, Unit.CELLS, Unit.WIDTH)], + ["1.4", Scalar(1.4, Unit.CELLS, Unit.WIDTH)], + [Scalar(100, Unit.CELLS, Unit.WIDTH), Scalar(100, Unit.CELLS, Unit.WIDTH)], + [Scalar(10.3, Unit.CELLS, Unit.WIDTH), Scalar(10.3, Unit.CELLS, Unit.WIDTH)], + [Scalar(10.4, Unit.CELLS, Unit.HEIGHT), Scalar(10.4, Unit.CELLS, Unit.HEIGHT)], + [Scalar(10.5, Unit.PERCENT, Unit.WIDTH), Scalar(10.5, Unit.WIDTH, Unit.WIDTH)], + [Scalar(10.6, Unit.PERCENT, Unit.PERCENT), Scalar(10.6, Unit.WIDTH, Unit.WIDTH)], + [Scalar(10.7, Unit.HEIGHT, Unit.PERCENT), Scalar(10.7, Unit.HEIGHT, Unit.PERCENT)], + # percentage values are normalised to floats and get the WIDTH "percent_unit": + [Scalar(11, Unit.PERCENT, Unit.HEIGHT), Scalar(11.0, Unit.WIDTH, Unit.WIDTH)], + # fmt: on + ], +) +def test_widget_style_size_can_accept_various_data_types_and_normalize_them( + size_dimension_input, size_dimension_expected_output +): + widget = Widget() + + widget.styles.width = size_dimension_input + assert widget.styles.width == size_dimension_expected_output + + +@pytest.mark.parametrize( + "size_dimension_input", + [ + "a", + "1.4e3", + 3.14j, + Decimal("3.14"), + list(), + tuple(), + dict(), + ], +) +def test_widget_style_size_fails_if_data_type_is_not_supported(size_dimension_input): + widget = Widget() + + with pytest.raises(StyleValueError): + widget.styles.width = size_dimension_input diff --git a/tests/test_widget.py b/tests/test_widget.py index 7eee43a54..abc92039c 100644 --- a/tests/test_widget.py +++ b/tests/test_widget.py @@ -1,16 +1,22 @@ +from contextlib import nullcontext as does_not_raise +from decimal import Decimal + import pytest from textual.css.errors import StyleValueError +from textual.css.scalar import Scalar, Unit from textual.widget import Widget @pytest.mark.parametrize( - "set_val, get_val, style_str", [ + "set_val, get_val, style_str", + [ [True, True, "visible"], [False, False, "hidden"], ["hidden", False, "hidden"], ["visible", True, "visible"], - ]) + ], +) def test_widget_set_visible_true(set_val, get_val, style_str): widget = Widget() widget.visible = set_val