Files
core/tests/helpers/template/extensions/test_string.py
2025-10-19 01:24:58 +02:00

134 lines
4.0 KiB
Python

"""Test string template extension."""
from __future__ import annotations
from homeassistant.core import HomeAssistant
from tests.helpers.template.helpers import render
def test_ordinal(hass: HomeAssistant) -> None:
"""Test the ordinal filter."""
tests = [
(1, "1st"),
(2, "2nd"),
(3, "3rd"),
(4, "4th"),
(5, "5th"),
(12, "12th"),
(100, "100th"),
(101, "101st"),
]
for value, expected in tests:
assert render(hass, f"{{{{ {value} | ordinal }}}}") == expected
def test_slugify(hass: HomeAssistant) -> None:
"""Test the slugify filter."""
# Test as global function
assert render(hass, '{{ slugify("Home Assistant") }}') == "home_assistant"
# Test as filter
assert render(hass, '{{ "Home Assistant" | slugify }}') == "home_assistant"
# Test with custom separator as global
assert render(hass, '{{ slugify("Home Assistant", "-") }}') == "home-assistant"
# Test with custom separator as filter
assert render(hass, '{{ "Home Assistant" | slugify("-") }}') == "home-assistant"
def test_urlencode(hass: HomeAssistant) -> None:
"""Test the urlencode method."""
# Test with dictionary
result = render(
hass, "{% set dict = {'foo': 'x&y', 'bar': 42} %}{{ dict | urlencode }}"
)
assert result == "foo=x%26y&bar=42"
# Test with string
result = render(
hass, "{% set string = 'the quick brown fox = true' %}{{ string | urlencode }}"
)
assert result == "the%20quick%20brown%20fox%20%3D%20true"
def test_string_functions_with_non_string_input(hass: HomeAssistant) -> None:
"""Test string functions with non-string input (automatic conversion)."""
# Test ordinal with integer
assert render(hass, "{{ 42 | ordinal }}") == "42nd"
# Test slugify with integer - Note: Jinja2 may return integer for simple cases
result = render(hass, "{{ 123 | slugify }}")
# Accept either string or integer result for simple numeric cases
assert result in ["123", 123]
def test_ordinal_edge_cases(hass: HomeAssistant) -> None:
"""Test ordinal function with edge cases."""
# Test teens (11th, 12th, 13th should all be 'th')
teens_tests = [
(11, "11th"),
(12, "12th"),
(13, "13th"),
(111, "111th"),
(112, "112th"),
(113, "113th"),
]
for value, expected in teens_tests:
assert render(hass, f"{{{{ {value} | ordinal }}}}") == expected
# Test other numbers ending in 1, 2, 3
other_tests = [
(21, "21st"),
(22, "22nd"),
(23, "23rd"),
(121, "121st"),
(122, "122nd"),
(123, "123rd"),
]
for value, expected in other_tests:
assert render(hass, f"{{{{ {value} | ordinal }}}}") == expected
def test_slugify_various_separators(hass: HomeAssistant) -> None:
"""Test slugify with various separators."""
test_cases = [
("Hello World", "_", "hello_world"),
("Hello World", "-", "hello-world"),
("Hello World", ".", "hello.world"),
("Hello-World_Test", "~", "hello~world~test"),
]
for text, separator, expected in test_cases:
# Test as global function
assert render(hass, f'{{{{ slugify("{text}", "{separator}") }}}}') == expected
# Test as filter
assert render(hass, f'{{{{ "{text}" | slugify("{separator}") }}}}') == expected
def test_urlencode_various_types(hass: HomeAssistant) -> None:
"""Test urlencode with various data types."""
# Test with nested dictionary values
result = render(
hass,
"{% set data = {'key': 'value with spaces', 'num': 123} %}{{ data | urlencode }}",
)
# URL encoding can have different order, so check both parts are present
# Note: urllib.parse.urlencode uses + for spaces in form data
assert "key=value+with+spaces" in result
assert "num=123" in result
# Test with special characters
result = render(
hass, "{% set data = {'special': 'a+b=c&d'} %}{{ data | urlencode }}"
)
assert result == "special=a%2Bb%3Dc%26d"