File: test_styles.py

package info (click to toggle)
textual 2.1.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 55,084 kB
  • sloc: python: 85,423; lisp: 1,669; makefile: 101
file content (205 lines) | stat: -rw-r--r-- 6,196 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
from decimal import Decimal

import pytest
from rich.style import Style

from textual.color import Color
from textual.css.errors import StyleValueError
from textual.css.scalar import Scalar, Unit
from textual.css.styles import RenderStyles, Styles
from textual.dom import DOMNode
from textual.widget import Widget


def test_styles_reset():
    styles = Styles()
    styles.text_style = "not bold"
    assert styles.text_style == Style(bold=False)
    styles.reset()
    assert styles.text_style is Style.null()


def test_has_rule():
    styles = Styles()
    assert not styles.has_rule("text_style")
    styles.text_style = "bold"
    assert styles.has_rule("text_style")
    styles.text_style = None
    assert not styles.has_rule("text_style")


def test_clear_rule():
    styles = Styles()
    styles.text_style = "bold"
    assert styles.has_rule("text_style")
    styles.clear_rule("text_style")
    assert not styles.has_rule("text_style")


def test_get_rules():
    styles = Styles()
    # Empty rules at start
    assert styles.get_rules() == {}
    styles.text_style = "bold"
    assert styles.get_rules() == {"text_style": Style.parse("bold")}
    styles.display = "none"
    assert styles.get_rules() == {
        "text_style": Style.parse("bold"),
        "display": "none",
    }


def test_set_rule():
    styles = Styles()
    assert styles.get_rules() == {}
    styles.set_rule("text_style", Style.parse("bold"))
    assert styles.get_rules() == {"text_style": Style.parse("bold")}


def test_reset():
    styles = Styles()
    assert styles.get_rules() == {}
    styles.set_rule("text_style", Style.parse("bold"))
    assert styles.get_rules() == {"text_style": Style.parse("bold")}
    styles.reset()
    assert styles.get_rules() == {}


def test_merge():
    styles = Styles()
    styles.set_rule("text_style", Style.parse("bold"))
    styles2 = Styles()
    styles2.set_rule("display", "none")
    styles.merge(styles2)
    assert styles.get_rules() == {
        "text_style": Style.parse("bold"),
        "display": "none",
    }


def test_merge_rules():
    styles = Styles()
    styles.set_rule("text_style", Style.parse("bold"))
    styles.merge_rules({"display": "none"})
    assert styles.get_rules() == {
        "text_style": Style.parse("bold"),
        "display": "none",
    }


def test_render_styles_border():
    base = Styles()
    inline = Styles()
    styles_view = RenderStyles(None, base, inline)

    base.border_top = ("heavy", "red")
    # Base has border-top: heavy red
    assert styles_view.border_top == ("heavy", Color.parse("red"))

    inline.border_left = ("round", "green")
    # Base has border-top heavy red, inline has border-left: round green
    assert styles_view.border_top == ("heavy", Color.parse("red"))
    assert styles_view.border_left == ("round", Color.parse("green"))
    assert styles_view.border == (
        ("heavy", Color.parse("red")),
        ("", Color(0, 255, 0)),
        ("", Color(0, 255, 0)),
        ("round", Color.parse("green")),
    )


def test_get_opacity_default():
    styles = RenderStyles(DOMNode(), Styles(), Styles())
    assert styles.text_opacity == 1.0


def test_styles_css_property():
    css = "opacity: 50%; text-opacity: 20%; background: green; color: red; tint: dodgerblue 20%;"
    styles = Styles().parse(css, read_from=("", ""))
    assert styles.css == (
        "background: #008000;\n"
        "color: #FF0000;\n"
        "opacity: 0.5;\n"
        "text-opacity: 0.2;\n"
        "tint: rgba(30,144,255,0.2);"
    )


@pytest.mark.parametrize(
    "set_value, expected",
    [
        [0.2, 0.2],
        [-0.4, 0.0],
        [5.8, 1.0],
        ["25%", 0.25],
        ["-10%", 0.0],
        ["120%", 1.0],
    ],
)
def test_opacity_set_then_get(set_value, expected):
    styles = RenderStyles(DOMNode(), Styles(), Styles())
    styles.text_opacity = set_value
    assert styles.text_opacity == expected


def test_opacity_set_invalid_type_error():
    styles = RenderStyles(DOMNode(), Styles(), Styles())
    with pytest.raises(StyleValueError):
        styles.text_opacity = "invalid value"


def test_opacity_set_allows_integer_value():
    """Regression test for https://github.com/Textualize/textual/issues/3414"""
    styles = RenderStyles(DOMNode(), Styles(), Styles())
    styles.text_opacity = 0
    assert styles.text_opacity == 0.0


@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