mirror of
https://github.com/home-assistant/core.git
synced 2025-11-13 04:50:17 +00:00
Streamline template tests (#154586)
This commit is contained in:
@@ -5,7 +5,8 @@ from __future__ import annotations
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import template
|
||||
|
||||
from tests.helpers.template.helpers import render
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -18,26 +19,19 @@ from homeassistant.helpers import template
|
||||
)
|
||||
def test_base64_encode(hass: HomeAssistant, value_template: str, expected: str) -> None:
|
||||
"""Test the base64_encode filter."""
|
||||
assert template.Template(value_template, hass).async_render() == expected
|
||||
assert render(hass, value_template) == expected
|
||||
|
||||
|
||||
def test_base64_decode(hass: HomeAssistant) -> None:
|
||||
"""Test the base64_decode filter."""
|
||||
assert (
|
||||
template.Template(
|
||||
'{{ "aG9tZWFzc2lzdGFudA==" | base64_decode }}', hass
|
||||
).async_render()
|
||||
== "homeassistant"
|
||||
render(hass, '{{ "aG9tZWFzc2lzdGFudA==" | base64_decode }}') == "homeassistant"
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
'{{ "aG9tZWFzc2lzdGFudA==" | base64_decode(None) }}', hass
|
||||
).async_render()
|
||||
render(hass, '{{ "aG9tZWFzc2lzdGFudA==" | base64_decode(None) }}')
|
||||
== b"homeassistant"
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
'{{ "aG9tZWFzc2lzdGFudA==" | base64_decode("ascii") }}', hass
|
||||
).async_render()
|
||||
render(hass, '{{ "aG9tZWFzc2lzdGFudA==" | base64_decode("ascii") }}')
|
||||
== "homeassistant"
|
||||
)
|
||||
|
||||
@@ -8,7 +8,8 @@ import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import template
|
||||
|
||||
from tests.helpers.template.helpers import render
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -27,10 +28,7 @@ from homeassistant.helpers import template
|
||||
)
|
||||
def test_is_list(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
"""Test list test."""
|
||||
assert (
|
||||
template.Template("{{ value is list }}", hass).async_render({"value": value})
|
||||
== expected
|
||||
)
|
||||
assert render(hass, "{{ value is list }}", {"value": value}) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -49,10 +47,7 @@ def test_is_list(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
)
|
||||
def test_is_set(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
"""Test set test."""
|
||||
assert (
|
||||
template.Template("{{ value is set }}", hass).async_render({"value": value})
|
||||
== expected
|
||||
)
|
||||
assert render(hass, "{{ value is set }}", {"value": value}) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -71,10 +66,7 @@ def test_is_set(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
)
|
||||
def test_is_tuple(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
"""Test tuple test."""
|
||||
assert (
|
||||
template.Template("{{ value is tuple }}", hass).async_render({"value": value})
|
||||
== expected
|
||||
)
|
||||
assert render(hass, "{{ value is tuple }}", {"value": value}) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -93,8 +85,7 @@ def test_is_tuple(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
def test_set(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
"""Test set conversion."""
|
||||
assert (
|
||||
template.Template("{{ set(value) }}", hass).async_render({"value": value})
|
||||
== list(expected.values())[0]
|
||||
render(hass, "{{ set(value) }}", {"value": value}) == list(expected.values())[0]
|
||||
)
|
||||
|
||||
|
||||
@@ -113,9 +104,7 @@ def test_set(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
)
|
||||
def test_tuple(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
"""Test tuple conversion."""
|
||||
result = template.Template("{{ tuple(value) }}", hass).async_render(
|
||||
{"value": value}
|
||||
)
|
||||
result = render(hass, "{{ tuple(value) }}", {"value": value})
|
||||
expected_value = list(expected.values())[0]
|
||||
if isinstance(value, set): # Sets don't have predictable order
|
||||
assert set(result) == set(expected_value)
|
||||
@@ -133,18 +122,11 @@ def test_tuple(hass: HomeAssistant, value: Any, expected: bool) -> None:
|
||||
)
|
||||
def test_zip(hass: HomeAssistant, cola, colb, expected) -> None:
|
||||
"""Test zip."""
|
||||
assert (
|
||||
template.Template("{{ zip(cola, colb) | list }}", hass).async_render(
|
||||
{"cola": cola, "colb": colb}
|
||||
)
|
||||
== expected
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
"[{% for a, b in zip(cola, colb) %}({{a}}, {{b}}), {% endfor %}]", hass
|
||||
).async_render({"cola": cola, "colb": colb})
|
||||
== expected
|
||||
)
|
||||
for tpl in (
|
||||
"{{ zip(cola, colb) | list }}",
|
||||
"[{% for a, b in zip(cola, colb) %}({{a}}, {{b}}), {% endfor %}]",
|
||||
):
|
||||
assert render(hass, tpl, {"cola": cola, "colb": colb}) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -156,38 +138,27 @@ def test_zip(hass: HomeAssistant, cola, colb, expected) -> None:
|
||||
)
|
||||
def test_unzip(hass: HomeAssistant, col, expected) -> None:
|
||||
"""Test unzipping using zip."""
|
||||
assert (
|
||||
template.Template("{{ zip(*col) | list }}", hass).async_render({"col": col})
|
||||
== expected
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
"{% set a, b = zip(*col) %}[{{a}}, {{b}}]", hass
|
||||
).async_render({"col": col})
|
||||
== expected
|
||||
)
|
||||
for tpl in (
|
||||
"{{ zip(*col) | list }}",
|
||||
"{% set a, b = zip(*col) %}[{{a}}, {{b}}]",
|
||||
):
|
||||
assert render(hass, tpl, {"col": col}) == expected
|
||||
|
||||
|
||||
def test_shuffle(hass: HomeAssistant) -> None:
|
||||
"""Test shuffle."""
|
||||
# Test basic shuffle
|
||||
result = template.Template("{{ shuffle([1, 2, 3, 4, 5]) }}", hass).async_render()
|
||||
result = render(hass, "{{ shuffle([1, 2, 3, 4, 5]) }}")
|
||||
assert len(result) == 5
|
||||
assert set(result) == {1, 2, 3, 4, 5}
|
||||
|
||||
# Test shuffle with seed
|
||||
result1 = template.Template(
|
||||
"{{ shuffle([1, 2, 3, 4, 5], seed=42) }}", hass
|
||||
).async_render()
|
||||
result2 = template.Template(
|
||||
"{{ shuffle([1, 2, 3, 4, 5], seed=42) }}", hass
|
||||
).async_render()
|
||||
result1 = render(hass, "{{ shuffle([1, 2, 3, 4, 5], seed=42) }}")
|
||||
result2 = render(hass, "{{ shuffle([1, 2, 3, 4, 5], seed=42) }}")
|
||||
assert result1 == result2 # Same seed should give same result
|
||||
|
||||
# Test shuffle with different seed
|
||||
result3 = template.Template(
|
||||
"{{ shuffle([1, 2, 3, 4, 5], seed=123) }}", hass
|
||||
).async_render()
|
||||
result3 = render(hass, "{{ shuffle([1, 2, 3, 4, 5], seed=123) }}")
|
||||
# Different seeds should usually give different results
|
||||
# (but we can't guarantee it for small lists)
|
||||
assert len(result3) == 5
|
||||
@@ -197,144 +168,115 @@ def test_shuffle(hass: HomeAssistant) -> None:
|
||||
def test_flatten(hass: HomeAssistant) -> None:
|
||||
"""Test flatten."""
|
||||
# Test basic flattening
|
||||
assert template.Template(
|
||||
"{{ flatten([[1, 2], [3, 4]]) }}", hass
|
||||
).async_render() == [1, 2, 3, 4]
|
||||
assert render(hass, "{{ flatten([[1, 2], [3, 4]]) }}") == [1, 2, 3, 4]
|
||||
|
||||
# Test nested flattening
|
||||
assert template.Template(
|
||||
"{{ flatten([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) }}", hass
|
||||
).async_render() == [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
expected = [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
assert (
|
||||
render(hass, "{{ flatten([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) }}") == expected
|
||||
)
|
||||
|
||||
# Test flattening with levels
|
||||
assert template.Template(
|
||||
"{{ flatten([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], levels=1) }}", hass
|
||||
).async_render() == [[1, 2], [3, 4], [5, 6], [7, 8]]
|
||||
assert render(
|
||||
hass, "{{ flatten([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], levels=1) }}"
|
||||
) == [[1, 2], [3, 4], [5, 6], [7, 8]]
|
||||
|
||||
# Test mixed types
|
||||
assert template.Template(
|
||||
"{{ flatten([[1, 'a'], [2, 'b']]) }}", hass
|
||||
).async_render() == [1, "a", 2, "b"]
|
||||
assert render(hass, "{{ flatten([[1, 'a'], [2, 'b']]) }}") == [1, "a", 2, "b"]
|
||||
|
||||
# Test empty list
|
||||
assert template.Template("{{ flatten([]) }}", hass).async_render() == []
|
||||
assert render(hass, "{{ flatten([]) }}") == []
|
||||
|
||||
# Test single level
|
||||
assert template.Template("{{ flatten([1, 2, 3]) }}", hass).async_render() == [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
assert render(hass, "{{ flatten([1, 2, 3]) }}") == [1, 2, 3]
|
||||
|
||||
|
||||
def test_intersect(hass: HomeAssistant) -> None:
|
||||
"""Test intersect."""
|
||||
# Test basic intersection
|
||||
result = template.Template(
|
||||
"{{ [1, 2, 3, 4] | intersect([3, 4, 5, 6]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [1, 2, 3, 4] | intersect([3, 4, 5, 6]) | sort }}")
|
||||
assert result == [3, 4]
|
||||
|
||||
# Test no intersection
|
||||
result = template.Template("{{ [1, 2] | intersect([3, 4]) }}", hass).async_render()
|
||||
result = render(hass, "{{ [1, 2] | intersect([3, 4]) }}")
|
||||
assert result == []
|
||||
|
||||
# Test string intersection
|
||||
result = template.Template(
|
||||
"{{ ['a', 'b', 'c'] | intersect(['b', 'c', 'd']) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ ['a', 'b', 'c'] | intersect(['b', 'c', 'd']) | sort }}")
|
||||
assert result == ["b", "c"]
|
||||
|
||||
# Test empty list intersection
|
||||
result = template.Template("{{ [] | intersect([1, 2, 3]) }}", hass).async_render()
|
||||
result = render(hass, "{{ [] | intersect([1, 2, 3]) }}")
|
||||
assert result == []
|
||||
|
||||
|
||||
def test_difference(hass: HomeAssistant) -> None:
|
||||
"""Test difference."""
|
||||
# Test basic difference
|
||||
result = template.Template(
|
||||
"{{ [1, 2, 3, 4] | difference([3, 4, 5, 6]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [1, 2, 3, 4] | difference([3, 4, 5, 6]) | sort }}")
|
||||
assert result == [1, 2]
|
||||
|
||||
# Test no difference
|
||||
result = template.Template(
|
||||
"{{ [1, 2] | difference([1, 2, 3, 4]) }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [1, 2] | difference([1, 2, 3, 4]) }}")
|
||||
assert result == []
|
||||
|
||||
# Test string difference
|
||||
result = template.Template(
|
||||
"{{ ['a', 'b', 'c'] | difference(['b', 'c', 'd']) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ ['a', 'b', 'c'] | difference(['b', 'c', 'd']) | sort }}")
|
||||
assert result == ["a"]
|
||||
|
||||
# Test empty list difference
|
||||
result = template.Template("{{ [] | difference([1, 2, 3]) }}", hass).async_render()
|
||||
result = render(hass, "{{ [] | difference([1, 2, 3]) }}")
|
||||
assert result == []
|
||||
|
||||
|
||||
def test_union(hass: HomeAssistant) -> None:
|
||||
"""Test union."""
|
||||
# Test basic union
|
||||
result = template.Template(
|
||||
"{{ [1, 2, 3] | union([3, 4, 5]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [1, 2, 3] | union([3, 4, 5]) | sort }}")
|
||||
assert result == [1, 2, 3, 4, 5]
|
||||
|
||||
# Test string union
|
||||
result = template.Template(
|
||||
"{{ ['a', 'b'] | union(['b', 'c']) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ ['a', 'b'] | union(['b', 'c']) | sort }}")
|
||||
assert result == ["a", "b", "c"]
|
||||
|
||||
# Test empty list union
|
||||
result = template.Template(
|
||||
"{{ [] | union([1, 2, 3]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [] | union([1, 2, 3]) | sort }}")
|
||||
assert result == [1, 2, 3]
|
||||
|
||||
# Test duplicate elements
|
||||
result = template.Template(
|
||||
"{{ [1, 1, 2, 2] | union([2, 2, 3, 3]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [1, 1, 2, 2] | union([2, 2, 3, 3]) | sort }}")
|
||||
assert result == [1, 2, 3]
|
||||
|
||||
|
||||
def test_symmetric_difference(hass: HomeAssistant) -> None:
|
||||
"""Test symmetric_difference."""
|
||||
# Test basic symmetric difference
|
||||
result = template.Template(
|
||||
"{{ [1, 2, 3, 4] | symmetric_difference([3, 4, 5, 6]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(
|
||||
hass, "{{ [1, 2, 3, 4] | symmetric_difference([3, 4, 5, 6]) | sort }}"
|
||||
)
|
||||
assert result == [1, 2, 5, 6]
|
||||
|
||||
# Test no symmetric difference (identical sets)
|
||||
result = template.Template(
|
||||
"{{ [1, 2, 3] | symmetric_difference([1, 2, 3]) }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [1, 2, 3] | symmetric_difference([1, 2, 3]) }}")
|
||||
assert result == []
|
||||
|
||||
# Test string symmetric difference
|
||||
result = template.Template(
|
||||
"{{ ['a', 'b', 'c'] | symmetric_difference(['b', 'c', 'd']) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(
|
||||
hass, "{{ ['a', 'b', 'c'] | symmetric_difference(['b', 'c', 'd']) | sort }}"
|
||||
)
|
||||
assert result == ["a", "d"]
|
||||
|
||||
# Test empty list symmetric difference
|
||||
result = template.Template(
|
||||
"{{ [] | symmetric_difference([1, 2, 3]) | sort }}", hass
|
||||
).async_render()
|
||||
result = render(hass, "{{ [] | symmetric_difference([1, 2, 3]) | sort }}")
|
||||
assert result == [1, 2, 3]
|
||||
|
||||
|
||||
def test_collection_functions_as_tests(hass: HomeAssistant) -> None:
|
||||
"""Test that type checking functions work as tests."""
|
||||
# Test various type checking functions
|
||||
assert template.Template("{{ [1,2,3] is list }}", hass).async_render()
|
||||
assert template.Template("{{ set([1,2,3]) is set }}", hass).async_render()
|
||||
assert template.Template("{{ (1,2,3) is tuple }}", hass).async_render()
|
||||
assert render(hass, "{{ [1,2,3] is list }}")
|
||||
assert render(hass, "{{ set([1,2,3]) is set }}")
|
||||
assert render(hass, "{{ (1,2,3) is tuple }}")
|
||||
|
||||
|
||||
def test_collection_error_handling(hass: HomeAssistant) -> None:
|
||||
@@ -342,16 +284,16 @@ def test_collection_error_handling(hass: HomeAssistant) -> None:
|
||||
|
||||
# Test flatten with non-iterable
|
||||
with pytest.raises(TemplateError, match="flatten expected a list"):
|
||||
template.Template("{{ flatten(123) }}", hass).async_render()
|
||||
render(hass, "{{ flatten(123) }}")
|
||||
|
||||
# Test intersect with non-iterable
|
||||
with pytest.raises(TemplateError, match="intersect expected a list"):
|
||||
template.Template("{{ [1, 2] | intersect(123) }}", hass).async_render()
|
||||
render(hass, "{{ [1, 2] | intersect(123) }}")
|
||||
|
||||
# Test difference with non-iterable
|
||||
with pytest.raises(TemplateError, match="difference expected a list"):
|
||||
template.Template("{{ [1, 2] | difference(123) }}", hass).async_render()
|
||||
render(hass, "{{ [1, 2] | difference(123) }}")
|
||||
|
||||
# Test shuffle with no arguments
|
||||
with pytest.raises(TemplateError, match="shuffle expected at least 1 argument"):
|
||||
template.Template("{{ shuffle() }}", hass).async_render()
|
||||
render(hass, "{{ shuffle() }}")
|
||||
|
||||
@@ -3,56 +3,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import template
|
||||
|
||||
from tests.helpers.template.helpers import render
|
||||
|
||||
|
||||
def test_md5(hass: HomeAssistant) -> None:
|
||||
"""Test the md5 function and filter."""
|
||||
assert (
|
||||
template.Template("{{ md5('Home Assistant') }}", hass).async_render()
|
||||
== "3d15e5c102c3413d0337393c3287e006"
|
||||
)
|
||||
|
||||
assert (
|
||||
template.Template("{{ 'Home Assistant' | md5 }}", hass).async_render()
|
||||
== "3d15e5c102c3413d0337393c3287e006"
|
||||
)
|
||||
ha_md5 = "3d15e5c102c3413d0337393c3287e006"
|
||||
assert render(hass, "{{ md5('Home Assistant') }}") == ha_md5
|
||||
assert render(hass, "{{ 'Home Assistant' | md5 }}") == ha_md5
|
||||
|
||||
|
||||
def test_sha1(hass: HomeAssistant) -> None:
|
||||
"""Test the sha1 function and filter."""
|
||||
assert (
|
||||
template.Template("{{ sha1('Home Assistant') }}", hass).async_render()
|
||||
== "c8fd3bb19b94312664faa619af7729bdbf6e9f8a"
|
||||
)
|
||||
|
||||
assert (
|
||||
template.Template("{{ 'Home Assistant' | sha1 }}", hass).async_render()
|
||||
== "c8fd3bb19b94312664faa619af7729bdbf6e9f8a"
|
||||
)
|
||||
ha_sha1 = "c8fd3bb19b94312664faa619af7729bdbf6e9f8a"
|
||||
assert render(hass, "{{ sha1('Home Assistant') }}") == ha_sha1
|
||||
assert render(hass, "{{ 'Home Assistant' | sha1 }}") == ha_sha1
|
||||
|
||||
|
||||
def test_sha256(hass: HomeAssistant) -> None:
|
||||
"""Test the sha256 function and filter."""
|
||||
assert (
|
||||
template.Template("{{ sha256('Home Assistant') }}", hass).async_render()
|
||||
== "2a366abb0cd47f51f3725bf0fb7ebcb4fefa6e20f4971e25fe2bb8da8145ce2b"
|
||||
)
|
||||
|
||||
assert (
|
||||
template.Template("{{ 'Home Assistant' | sha256 }}", hass).async_render()
|
||||
== "2a366abb0cd47f51f3725bf0fb7ebcb4fefa6e20f4971e25fe2bb8da8145ce2b"
|
||||
)
|
||||
ha_sha256 = "2a366abb0cd47f51f3725bf0fb7ebcb4fefa6e20f4971e25fe2bb8da8145ce2b"
|
||||
assert render(hass, "{{ sha256('Home Assistant') }}") == ha_sha256
|
||||
assert render(hass, "{{ 'Home Assistant' | sha256 }}") == ha_sha256
|
||||
|
||||
|
||||
def test_sha512(hass: HomeAssistant) -> None:
|
||||
"""Test the sha512 function and filter."""
|
||||
assert (
|
||||
template.Template("{{ sha512('Home Assistant') }}", hass).async_render()
|
||||
== "9e3c2cdd1fbab0037378d37e1baf8a3a4bf92c54b56ad1d459deee30ccbb2acbebd7a3614552ea08992ad27dedeb7b4c5473525ba90cb73dbe8b9ec5f69295bb"
|
||||
)
|
||||
|
||||
assert (
|
||||
template.Template("{{ 'Home Assistant' | sha512 }}", hass).async_render()
|
||||
== "9e3c2cdd1fbab0037378d37e1baf8a3a4bf92c54b56ad1d459deee30ccbb2acbebd7a3614552ea08992ad27dedeb7b4c5473525ba90cb73dbe8b9ec5f69295bb"
|
||||
)
|
||||
ha_sha512 = "9e3c2cdd1fbab0037378d37e1baf8a3a4bf92c54b56ad1d459deee30ccbb2acbebd7a3614552ea08992ad27dedeb7b4c5473525ba90cb73dbe8b9ec5f69295bb"
|
||||
assert render(hass, "{{ sha512('Home Assistant') }}") == ha_sha512
|
||||
assert render(hass, "{{ 'Home Assistant' | sha512 }}") == ha_sha512
|
||||
|
||||
@@ -8,7 +8,6 @@ import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import template
|
||||
|
||||
from tests.helpers.template.helpers import render
|
||||
|
||||
@@ -29,29 +28,19 @@ def test_logarithm(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, base, expected in tests:
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ {value} | log({base}) | round(1) }}}}", hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | log({base}) | round(1) }}}}") == expected
|
||||
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ log({value}, {base}) | round(1) }}}}", hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ log({value}, {base}) | round(1) }}}}") == expected
|
||||
|
||||
# Test handling of invalid input
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ invalid | log(_) }}", hass).async_render()
|
||||
render(hass, "{{ invalid | log(_) }}")
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ log(invalid, _) }}", hass).async_render()
|
||||
render(hass, "{{ log(invalid, _) }}")
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ 10 | log(invalid) }}", hass).async_render()
|
||||
render(hass, "{{ 10 | log(invalid) }}")
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ log(10, invalid) }}", hass).async_render()
|
||||
render(hass, "{{ log(10, invalid) }}")
|
||||
|
||||
# Test handling of default return value
|
||||
assert render(hass, "{{ 'no_number' | log(10, 1) }}") == 1
|
||||
@@ -73,19 +62,14 @@ def test_sine(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in tests:
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ {value} | sin | round(3) }}}}", hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | sin | round(3) }}}}") == expected
|
||||
assert render(hass, f"{{{{ sin({value}) | round(3) }}}}") == expected
|
||||
|
||||
# Test handling of invalid input
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ 'duck' | sin }}", hass).async_render()
|
||||
render(hass, "{{ 'duck' | sin }}")
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ invalid | sin('duck') }}", hass).async_render()
|
||||
render(hass, "{{ invalid | sin('duck') }}")
|
||||
|
||||
# Test handling of default return value
|
||||
assert render(hass, "{{ 'no_number' | sin(1) }}") == 1
|
||||
@@ -105,17 +89,12 @@ def test_cosine(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in tests:
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ {value} | cos | round(3) }}}}", hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | cos | round(3) }}}}") == expected
|
||||
assert render(hass, f"{{{{ cos({value}) | round(3) }}}}") == expected
|
||||
|
||||
# Test handling of invalid input
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ 'duck' | cos }}", hass).async_render()
|
||||
render(hass, "{{ 'duck' | cos }}")
|
||||
|
||||
# Test handling of default return value
|
||||
assert render(hass, "{{ 'no_number' | cos(1) }}") == 1
|
||||
@@ -134,17 +113,12 @@ def test_tangent(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in tests:
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ {value} | tan | round(3) }}}}", hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | tan | round(3) }}}}") == expected
|
||||
assert render(hass, f"{{{{ tan({value}) | round(3) }}}}") == expected
|
||||
|
||||
# Test handling of invalid input
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ 'duck' | tan }}", hass).async_render()
|
||||
render(hass, "{{ 'duck' | tan }}")
|
||||
|
||||
# Test handling of default return value
|
||||
assert render(hass, "{{ 'no_number' | tan(1) }}") == 1
|
||||
@@ -165,17 +139,14 @@ def test_square_root(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in tests:
|
||||
assert (
|
||||
template.Template(f"{{{{ {value} | sqrt }}}}", hass).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | sqrt }}}}") == expected
|
||||
assert render(hass, f"{{{{ sqrt({value}) }}}}") == expected
|
||||
|
||||
# Test handling of invalid input
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ 'duck' | sqrt }}", hass).async_render()
|
||||
render(hass, "{{ 'duck' | sqrt }}")
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ -1 | sqrt }}", hass).async_render()
|
||||
render(hass, "{{ -1 | sqrt }}")
|
||||
|
||||
# Test handling of default return value
|
||||
assert render(hass, "{{ 'no_number' | sqrt(1) }}") == 1
|
||||
@@ -217,114 +188,95 @@ def test_arc_functions(hass: HomeAssistant) -> None:
|
||||
|
||||
def test_average(hass: HomeAssistant) -> None:
|
||||
"""Test the average function."""
|
||||
assert template.Template("{{ average([1, 2, 3]) }}", hass).async_render() == 2
|
||||
assert template.Template("{{ average(1, 2, 3) }}", hass).async_render() == 2
|
||||
assert render(hass, "{{ average([1, 2, 3]) }}") == 2
|
||||
assert render(hass, "{{ average(1, 2, 3) }}") == 2
|
||||
|
||||
# Testing of default values
|
||||
assert template.Template("{{ average([1, 2, 3], -1) }}", hass).async_render() == 2
|
||||
assert template.Template("{{ average([], -1) }}", hass).async_render() == -1
|
||||
assert template.Template("{{ average([], default=-1) }}", hass).async_render() == -1
|
||||
assert (
|
||||
template.Template("{{ average([], 5, default=-1) }}", hass).async_render() == -1
|
||||
)
|
||||
assert (
|
||||
template.Template("{{ average(1, 'a', 3, default=-1) }}", hass).async_render()
|
||||
== -1
|
||||
)
|
||||
assert render(hass, "{{ average([1, 2, 3], -1) }}") == 2
|
||||
assert render(hass, "{{ average([], -1) }}") == -1
|
||||
assert render(hass, "{{ average([], default=-1) }}") == -1
|
||||
assert render(hass, "{{ average([], 5, default=-1) }}") == -1
|
||||
assert render(hass, "{{ average(1, 'a', 3, default=-1) }}") == -1
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ average() }}", hass).async_render()
|
||||
render(hass, "{{ average() }}")
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ average([]) }}", hass).async_render()
|
||||
render(hass, "{{ average([]) }}")
|
||||
|
||||
|
||||
def test_median(hass: HomeAssistant) -> None:
|
||||
"""Test the median function."""
|
||||
assert template.Template("{{ median([1, 2, 3]) }}", hass).async_render() == 2
|
||||
assert template.Template("{{ median([1, 2, 3, 4]) }}", hass).async_render() == 2.5
|
||||
assert template.Template("{{ median(1, 2, 3) }}", hass).async_render() == 2
|
||||
assert render(hass, "{{ median([1, 2, 3]) }}") == 2
|
||||
assert render(hass, "{{ median([1, 2, 3, 4]) }}") == 2.5
|
||||
assert render(hass, "{{ median(1, 2, 3) }}") == 2
|
||||
|
||||
# Testing of default values
|
||||
assert template.Template("{{ median([1, 2, 3], -1) }}", hass).async_render() == 2
|
||||
assert template.Template("{{ median([], -1) }}", hass).async_render() == -1
|
||||
assert template.Template("{{ median([], default=-1) }}", hass).async_render() == -1
|
||||
assert render(hass, "{{ median([1, 2, 3], -1) }}") == 2
|
||||
assert render(hass, "{{ median([], -1) }}") == -1
|
||||
assert render(hass, "{{ median([], default=-1) }}") == -1
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ median() }}", hass).async_render()
|
||||
render(hass, "{{ median() }}")
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ median([]) }}", hass).async_render()
|
||||
render(hass, "{{ median([]) }}")
|
||||
|
||||
|
||||
def test_statistical_mode(hass: HomeAssistant) -> None:
|
||||
"""Test the statistical mode function."""
|
||||
assert (
|
||||
template.Template("{{ statistical_mode([1, 1, 2, 3]) }}", hass).async_render()
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
template.Template("{{ statistical_mode(1, 1, 2, 3) }}", hass).async_render()
|
||||
== 1
|
||||
)
|
||||
assert render(hass, "{{ statistical_mode([1, 1, 2, 3]) }}") == 1
|
||||
assert render(hass, "{{ statistical_mode(1, 1, 2, 3) }}") == 1
|
||||
|
||||
# Testing of default values
|
||||
assert (
|
||||
template.Template("{{ statistical_mode([1, 1, 2], -1) }}", hass).async_render()
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
template.Template("{{ statistical_mode([], -1) }}", hass).async_render() == -1
|
||||
)
|
||||
assert (
|
||||
template.Template("{{ statistical_mode([], default=-1) }}", hass).async_render()
|
||||
== -1
|
||||
)
|
||||
assert render(hass, "{{ statistical_mode([1, 1, 2], -1) }}") == 1
|
||||
assert render(hass, "{{ statistical_mode([], -1) }}") == -1
|
||||
assert render(hass, "{{ statistical_mode([], default=-1) }}") == -1
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ statistical_mode() }}", hass).async_render()
|
||||
render(hass, "{{ statistical_mode() }}")
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ statistical_mode([]) }}", hass).async_render()
|
||||
render(hass, "{{ statistical_mode([]) }}")
|
||||
|
||||
|
||||
def test_min_max_functions(hass: HomeAssistant) -> None:
|
||||
"""Test min and max functions."""
|
||||
# Test min function
|
||||
assert template.Template("{{ min([1, 2, 3]) }}", hass).async_render() == 1
|
||||
assert template.Template("{{ min(1, 2, 3) }}", hass).async_render() == 1
|
||||
assert render(hass, "{{ min([1, 2, 3]) }}") == 1
|
||||
assert render(hass, "{{ min(1, 2, 3) }}") == 1
|
||||
|
||||
# Test max function
|
||||
assert template.Template("{{ max([1, 2, 3]) }}", hass).async_render() == 3
|
||||
assert template.Template("{{ max(1, 2, 3) }}", hass).async_render() == 3
|
||||
assert render(hass, "{{ max([1, 2, 3]) }}") == 3
|
||||
assert render(hass, "{{ max(1, 2, 3) }}") == 3
|
||||
|
||||
# Test error handling
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ min() }}", hass).async_render()
|
||||
render(hass, "{{ min() }}")
|
||||
|
||||
with pytest.raises(TemplateError):
|
||||
template.Template("{{ max() }}", hass).async_render()
|
||||
render(hass, "{{ max() }}")
|
||||
|
||||
|
||||
def test_bitwise_and(hass: HomeAssistant) -> None:
|
||||
"""Test bitwise and."""
|
||||
assert template.Template("{{ bitwise_and(8, 2) }}", hass).async_render() == 0
|
||||
assert template.Template("{{ bitwise_and(10, 2) }}", hass).async_render() == 2
|
||||
assert template.Template("{{ bitwise_and(8, 8) }}", hass).async_render() == 8
|
||||
assert render(hass, "{{ bitwise_and(8, 2) }}") == 0
|
||||
assert render(hass, "{{ bitwise_and(10, 2) }}") == 2
|
||||
assert render(hass, "{{ bitwise_and(8, 8) }}") == 8
|
||||
|
||||
|
||||
def test_bitwise_or(hass: HomeAssistant) -> None:
|
||||
"""Test bitwise or."""
|
||||
assert template.Template("{{ bitwise_or(8, 2) }}", hass).async_render() == 10
|
||||
assert template.Template("{{ bitwise_or(8, 8) }}", hass).async_render() == 8
|
||||
assert template.Template("{{ bitwise_or(10, 2) }}", hass).async_render() == 10
|
||||
assert render(hass, "{{ bitwise_or(8, 2) }}") == 10
|
||||
assert render(hass, "{{ bitwise_or(8, 8) }}") == 8
|
||||
assert render(hass, "{{ bitwise_or(10, 2) }}") == 10
|
||||
|
||||
|
||||
def test_bitwise_xor(hass: HomeAssistant) -> None:
|
||||
"""Test bitwise xor."""
|
||||
assert template.Template("{{ bitwise_xor(8, 2) }}", hass).async_render() == 10
|
||||
assert template.Template("{{ bitwise_xor(8, 8) }}", hass).async_render() == 0
|
||||
assert template.Template("{{ bitwise_xor(10, 2) }}", hass).async_render() == 8
|
||||
assert render(hass, "{{ bitwise_xor(8, 2) }}") == 10
|
||||
assert render(hass, "{{ bitwise_xor(8, 8) }}") == 0
|
||||
assert render(hass, "{{ bitwise_xor(10, 2) }}") == 8
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -361,30 +313,30 @@ def test_min_max_attribute(hass: HomeAssistant, attribute) -> None:
|
||||
},
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
render(
|
||||
hass,
|
||||
f"{{{{ (state_attr('test.object', 'objects') | min(attribute='{attribute}'))['{attribute}']}}}}",
|
||||
hass,
|
||||
).async_render()
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
render(
|
||||
hass,
|
||||
f"{{{{ (min(state_attr('test.object', 'objects'), attribute='{attribute}'))['{attribute}']}}}}",
|
||||
hass,
|
||||
).async_render()
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ (state_attr('test.object', 'objects') | max(attribute='{attribute}'))['{attribute}']}}}}",
|
||||
render(
|
||||
hass,
|
||||
).async_render()
|
||||
f"{{{{ (state_attr('test.object', 'objects') | max(attribute='{attribute}'))['{attribute}']}}}}",
|
||||
)
|
||||
== 3
|
||||
)
|
||||
assert (
|
||||
template.Template(
|
||||
f"{{{{ (max(state_attr('test.object', 'objects'), attribute='{attribute}'))['{attribute}']}}}}",
|
||||
render(
|
||||
hass,
|
||||
).async_render()
|
||||
f"{{{{ (max(state_attr('test.object', 'objects'), attribute='{attribute}'))['{attribute}']}}}}",
|
||||
)
|
||||
== 3
|
||||
)
|
||||
|
||||
@@ -6,260 +6,169 @@ import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import template
|
||||
|
||||
from tests.helpers.template.helpers import render
|
||||
|
||||
|
||||
def test_regex_match(hass: HomeAssistant) -> None:
|
||||
"""Test regex_match method."""
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ '123-456-7890' | regex_match('(\\d{3})-(\\d{3})-(\\d{4})') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Home Assistant test' | regex_match('home', True) }}
|
||||
""",
|
||||
hass,
|
||||
result = render(
|
||||
hass, r"""{{ '123-456-7890' | regex_match('(\\d{3})-(\\d{3})-(\\d{4})') }}"""
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
assert result is True
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Another Home Assistant test' | regex_match('Home') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is False
|
||||
result = render(hass, """{{ 'Home Assistant test' | regex_match('home', True) }}""")
|
||||
assert result is True
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ ['Home Assistant test'] | regex_match('.*Assist') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
result = render(hass, """{{ 'Another Home Assistant test'|regex_match('Home') }}""")
|
||||
assert result is False
|
||||
|
||||
result = render(hass, """{{ ['Home Assistant test'] | regex_match('.*Assist') }}""")
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_match_test(hass: HomeAssistant) -> None:
|
||||
"""Test match test."""
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ '123-456-7890' is match('(\\d{3})-(\\d{3})-(\\d{4})') }}
|
||||
""",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, r"""{{ '123-456-7890' is match('(\\d{3})-(\\d{3})-(\\d{4})') }}"""
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_regex_search(hass: HomeAssistant) -> None:
|
||||
"""Test regex_search method."""
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ '123-456-7890' | regex_search('(\\d{3})-(\\d{3})-(\\d{4})') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Home Assistant test' | regex_search('home', True) }}
|
||||
""",
|
||||
hass,
|
||||
result = render(
|
||||
hass, r"""{{ '123-456-7890' | regex_search('(\\d{3})-(\\d{3})-(\\d{4})') }}"""
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
assert result is True
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Another Home Assistant test' | regex_search('Home') }}
|
||||
""",
|
||||
hass,
|
||||
result = render(
|
||||
hass, """{{ 'Home Assistant test' | regex_search('home', True) }}"""
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
assert result is True
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ ['Home Assistant test'] | regex_search('Assist') }}
|
||||
""",
|
||||
hass,
|
||||
result = render(
|
||||
hass, """ {{ 'Another Home Assistant test' | regex_search('Home') }}"""
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
assert result is True
|
||||
|
||||
result = render(hass, """{{ ['Home Assistant test'] | regex_search('Assist') }}""")
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_search_test(hass: HomeAssistant) -> None:
|
||||
"""Test search test."""
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ '123-456-7890' is search('(\\d{3})-(\\d{3})-(\\d{4})') }}
|
||||
""",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, r"""{{ '123-456-7890' is search('(\\d{3})-(\\d{3})-(\\d{4})') }}"""
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_regex_replace(hass: HomeAssistant) -> None:
|
||||
"""Test regex_replace method."""
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ 'Hello World' | regex_replace('(Hello\\s)',) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() == "World"
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ ['Home hinderant test'] | regex_replace('hinder', 'Assist') }}
|
||||
""",
|
||||
hass,
|
||||
result = render(hass, r"""{{ 'Hello World' | regex_replace('(Hello\\s)',) }}""")
|
||||
assert result == "World"
|
||||
|
||||
result = render(
|
||||
hass, """{{ ['Home hinderant test'] | regex_replace('hinder', 'Assist') }}"""
|
||||
)
|
||||
assert tpl.async_render() == ["Home Assistant test"]
|
||||
assert result == ["Home Assistant test"]
|
||||
|
||||
|
||||
def test_regex_findall(hass: HomeAssistant) -> None:
|
||||
"""Test regex_findall method."""
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Flight from JFK to LHR' | regex_findall('([A-Z]{3})') }}
|
||||
""",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, """{{ 'Flight from JFK to LHR' | regex_findall('([A-Z]{3})') }}"""
|
||||
)
|
||||
assert tpl.async_render() == ["JFK", "LHR"]
|
||||
assert result == ["JFK", "LHR"]
|
||||
|
||||
|
||||
def test_regex_findall_index(hass: HomeAssistant) -> None:
|
||||
"""Test regex_findall_index method."""
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Flight from JFK to LHR' | regex_findall_index('([A-Z]{3})', 0) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() == "JFK"
|
||||
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'Flight from JFK to LHR' | regex_findall_index('([A-Z]{3})', 1) }}
|
||||
""",
|
||||
result = render(
|
||||
hass,
|
||||
"""{{ 'Flight from JFK to LHR' | regex_findall_index('([A-Z]{3})', 0) }}""",
|
||||
)
|
||||
assert tpl.async_render() == "LHR"
|
||||
assert result == "JFK"
|
||||
|
||||
result = render(
|
||||
hass,
|
||||
"""{{ 'Flight from JFK to LHR' | regex_findall_index('([A-Z]{3})', 1) }}""",
|
||||
)
|
||||
assert result == "LHR"
|
||||
|
||||
|
||||
def test_regex_ignorecase_parameter(hass: HomeAssistant) -> None:
|
||||
"""Test ignorecase parameter across all regex functions."""
|
||||
# Test regex_match with ignorecase
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'TEST' | regex_match('test', True) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
result = render(hass, """{{ 'TEST' | regex_match('test', True) }}""")
|
||||
assert result is True
|
||||
|
||||
# Test regex_search with ignorecase
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'TEST STRING' | regex_search('test', True) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
result = render(hass, """{{ 'TEST STRING' | regex_search('test', True) }}""")
|
||||
assert result is True
|
||||
|
||||
# Test regex_replace with ignorecase
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'TEST' | regex_replace('test', 'replaced', True) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() == "replaced"
|
||||
|
||||
result = render(hass, """{{ 'TEST' | regex_replace('test', 'replaced', True) }}""")
|
||||
assert result == "replaced"
|
||||
|
||||
# Test regex_findall with ignorecase
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'TEST test Test' | regex_findall('test', True) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() == ["TEST", "test", "Test"]
|
||||
|
||||
result = render(hass, """{{ 'TEST test Test' | regex_findall('test', True) }}""")
|
||||
assert result == ["TEST", "test", "Test"]
|
||||
|
||||
|
||||
def test_regex_with_non_string_input(hass: HomeAssistant) -> None:
|
||||
"""Test regex functions with non-string input (automatic conversion)."""
|
||||
# Test with integer
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ 12345 | regex_match('\\d+') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
result = render(hass, r"""{{ 12345 | regex_match('\\d+') }}""")
|
||||
assert result is True
|
||||
|
||||
# Test with list (string conversion)
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ [1, 2, 3] | regex_search('\\d') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
result = render(hass, r"""{{ [1, 2, 3] | regex_search('\\d') }}""")
|
||||
assert result is True
|
||||
|
||||
|
||||
def test_regex_edge_cases(hass: HomeAssistant) -> None:
|
||||
"""Test regex functions with edge cases."""
|
||||
# Test with empty string
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ '' | regex_match('.*') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
assert tpl.async_render() is True
|
||||
|
||||
assert render(hass, """{{ '' | regex_match('.*') }}""") is True
|
||||
|
||||
# Test regex_findall_index with out of bounds index
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'test' | regex_findall_index('t', 5) }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
with pytest.raises(TemplateError):
|
||||
tpl.async_render()
|
||||
render(hass, """{{ 'test' | regex_findall_index('t', 5) }}""")
|
||||
|
||||
# Test with invalid regex pattern
|
||||
tpl = template.Template(
|
||||
"""
|
||||
{{ 'test' | regex_match('[') }}
|
||||
""",
|
||||
hass,
|
||||
)
|
||||
with pytest.raises(TemplateError): # re.error wrapped in TemplateError
|
||||
tpl.async_render()
|
||||
render(hass, """{{ 'test' | regex_match('[') }}""")
|
||||
|
||||
|
||||
def test_regex_groups_and_replacement_patterns(hass: HomeAssistant) -> None:
|
||||
"""Test regex with groups and replacement patterns."""
|
||||
# Test replacement with groups
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ 'John Doe' | regex_replace('(\\w+) (\\w+)', '\\2, \\1') }}
|
||||
""",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, r"""{{ 'John Doe' | regex_replace('(\\w+) (\\w+)', '\\2, \\1') }}"""
|
||||
)
|
||||
assert tpl.async_render() == "Doe, John"
|
||||
assert result == "Doe, John"
|
||||
|
||||
# Test findall with groups
|
||||
tpl = template.Template(
|
||||
r"""
|
||||
{{ 'Email: test@example.com, Phone: 123-456-7890' | regex_findall('(\\w+@\\w+\\.\\w+)|(\\d{3}-\\d{3}-\\d{4})') }}
|
||||
""",
|
||||
result = render(
|
||||
hass,
|
||||
r"""{{ 'Email: test@example.com, Phone: 123-456-7890' | regex_findall('(\\w+@\\w+\\.\\w+)|(\\d{3}-\\d{3}-\\d{4})') }}""",
|
||||
)
|
||||
result = tpl.async_render()
|
||||
# The result will contain tuples with empty strings for non-matching groups
|
||||
assert len(result) == 2
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import template
|
||||
|
||||
from tests.helpers.template.helpers import render
|
||||
|
||||
|
||||
def test_ordinal(hass: HomeAssistant) -> None:
|
||||
@@ -20,63 +21,48 @@ def test_ordinal(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in tests:
|
||||
assert (
|
||||
template.Template(f"{{{{ {value} | ordinal }}}}", hass).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | ordinal }}}}") == expected
|
||||
|
||||
|
||||
def test_slugify(hass: HomeAssistant) -> None:
|
||||
"""Test the slugify filter."""
|
||||
# Test as global function
|
||||
assert (
|
||||
template.Template('{{ slugify("Home Assistant") }}', hass).async_render()
|
||||
== "home_assistant"
|
||||
)
|
||||
assert render(hass, '{{ slugify("Home Assistant") }}') == "home_assistant"
|
||||
|
||||
# Test as filter
|
||||
assert (
|
||||
template.Template('{{ "Home Assistant" | slugify }}', hass).async_render()
|
||||
== "home_assistant"
|
||||
)
|
||||
assert render(hass, '{{ "Home Assistant" | slugify }}') == "home_assistant"
|
||||
|
||||
# Test with custom separator as global
|
||||
assert (
|
||||
template.Template('{{ slugify("Home Assistant", "-") }}', hass).async_render()
|
||||
== "home-assistant"
|
||||
)
|
||||
assert render(hass, '{{ slugify("Home Assistant", "-") }}') == "home-assistant"
|
||||
|
||||
# Test with custom separator as filter
|
||||
assert (
|
||||
template.Template('{{ "Home Assistant" | slugify("-") }}', hass).async_render()
|
||||
== "home-assistant"
|
||||
)
|
||||
assert render(hass, '{{ "Home Assistant" | slugify("-") }}') == "home-assistant"
|
||||
|
||||
|
||||
def test_urlencode(hass: HomeAssistant) -> None:
|
||||
"""Test the urlencode method."""
|
||||
# Test with dictionary
|
||||
tpl = template.Template(
|
||||
"{% set dict = {'foo': 'x&y', 'bar': 42} %}{{ dict | urlencode }}",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, "{% set dict = {'foo': 'x&y', 'bar': 42} %}{{ dict | urlencode }}"
|
||||
)
|
||||
assert tpl.async_render() == "foo=x%26y&bar=42"
|
||||
assert result == "foo=x%26y&bar=42"
|
||||
|
||||
# Test with string
|
||||
tpl = template.Template(
|
||||
"{% set string = 'the quick brown fox = true' %}{{ string | urlencode }}",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, "{% set string = 'the quick brown fox = true' %}{{ string | urlencode }}"
|
||||
)
|
||||
assert tpl.async_render() == "the%20quick%20brown%20fox%20%3D%20true"
|
||||
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 template.Template("{{ 42 | ordinal }}", hass).async_render() == "42nd"
|
||||
assert render(hass, "{{ 42 | ordinal }}") == "42nd"
|
||||
|
||||
# Test slugify with integer - Note: Jinja2 may return integer for simple cases
|
||||
result = template.Template("{{ 123 | slugify }}", hass).async_render()
|
||||
result = render(hass, "{{ 123 | slugify }}")
|
||||
# Accept either string or integer result for simple numeric cases
|
||||
assert result in ["123", 123]
|
||||
|
||||
@@ -94,10 +80,7 @@ def test_ordinal_edge_cases(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in teens_tests:
|
||||
assert (
|
||||
template.Template(f"{{{{ {value} | ordinal }}}}", hass).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | ordinal }}}}") == expected
|
||||
|
||||
# Test other numbers ending in 1, 2, 3
|
||||
other_tests = [
|
||||
@@ -110,10 +93,7 @@ def test_ordinal_edge_cases(hass: HomeAssistant) -> None:
|
||||
]
|
||||
|
||||
for value, expected in other_tests:
|
||||
assert (
|
||||
template.Template(f"{{{{ {value} | ordinal }}}}", hass).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f"{{{{ {value} | ordinal }}}}") == expected
|
||||
|
||||
|
||||
def test_slugify_various_separators(hass: HomeAssistant) -> None:
|
||||
@@ -127,38 +107,27 @@ def test_slugify_various_separators(hass: HomeAssistant) -> None:
|
||||
|
||||
for text, separator, expected in test_cases:
|
||||
# Test as global function
|
||||
assert (
|
||||
template.Template(
|
||||
f'{{{{ slugify("{text}", "{separator}") }}}}', hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
assert render(hass, f'{{{{ slugify("{text}", "{separator}") }}}}') == expected
|
||||
|
||||
# Test as filter
|
||||
assert (
|
||||
template.Template(
|
||||
f'{{{{ "{text}" | slugify("{separator}") }}}}', hass
|
||||
).async_render()
|
||||
== expected
|
||||
)
|
||||
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
|
||||
tpl = template.Template(
|
||||
"{% set data = {'key': 'value with spaces', 'num': 123} %}{{ data | urlencode }}",
|
||||
result = render(
|
||||
hass,
|
||||
"{% set data = {'key': 'value with spaces', 'num': 123} %}{{ data | urlencode }}",
|
||||
)
|
||||
result = tpl.async_render()
|
||||
# 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
|
||||
tpl = template.Template(
|
||||
"{% set data = {'special': 'a+b=c&d'} %}{{ data | urlencode }}",
|
||||
hass,
|
||||
|
||||
result = render(
|
||||
hass, "{% set data = {'special': 'a+b=c&d'} %}{{ data | urlencode }}"
|
||||
)
|
||||
assert tpl.async_render() == "special=a%2Bb%3Dc%26d"
|
||||
assert result == "special=a%2Bb%3Dc%26d"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,14 @@ from homeassistant.helpers.template.render_info import (
|
||||
)
|
||||
|
||||
|
||||
def test_render_info_initialization(hass: HomeAssistant) -> None:
|
||||
@pytest.fixture
|
||||
def template_obj(hass: HomeAssistant) -> template.Template:
|
||||
"""Template object for test_render_info."""
|
||||
return template.Template("{{ 1 + 1 }}", hass)
|
||||
|
||||
|
||||
def test_render_info_initialization(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo initialization."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
assert info.template is template_obj
|
||||
@@ -37,9 +42,8 @@ def test_render_info_initialization(hass: HomeAssistant) -> None:
|
||||
assert info.filter is _true
|
||||
|
||||
|
||||
def test_render_info_repr(hass: HomeAssistant) -> None:
|
||||
def test_render_info_repr(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo representation."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
info.domains.add("sensor")
|
||||
info.entities.add("sensor.test")
|
||||
@@ -50,9 +54,8 @@ def test_render_info_repr(hass: HomeAssistant) -> None:
|
||||
assert "entities={'sensor.test'}" in repr_str
|
||||
|
||||
|
||||
def test_render_info_result(hass: HomeAssistant) -> None:
|
||||
def test_render_info_result(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo result property."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
# Test with no result set - should return None cast as str
|
||||
@@ -68,9 +71,10 @@ def test_render_info_result(hass: HomeAssistant) -> None:
|
||||
info.result()
|
||||
|
||||
|
||||
def test_render_info_filter_domains_and_entities(hass: HomeAssistant) -> None:
|
||||
def test_render_info_filter_domains_and_entities(
|
||||
template_obj: template.Template,
|
||||
) -> None:
|
||||
"""Test RenderInfo entity and domain filtering."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
# Add domain and entity
|
||||
@@ -85,9 +89,8 @@ def test_render_info_filter_domains_and_entities(hass: HomeAssistant) -> None:
|
||||
assert info._filter_domains_and_entities("switch.kitchen") is False
|
||||
|
||||
|
||||
def test_render_info_filter_entities(hass: HomeAssistant) -> None:
|
||||
def test_render_info_filter_entities(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo entity-only filtering."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
info.entities.add("sensor.test")
|
||||
@@ -96,9 +99,8 @@ def test_render_info_filter_entities(hass: HomeAssistant) -> None:
|
||||
assert info._filter_entities("sensor.other") is False
|
||||
|
||||
|
||||
def test_render_info_filter_lifecycle_domains(hass: HomeAssistant) -> None:
|
||||
def test_render_info_filter_lifecycle_domains(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo domain lifecycle filtering."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
info.domains_lifecycle.add("sensor")
|
||||
@@ -107,9 +109,8 @@ def test_render_info_filter_lifecycle_domains(hass: HomeAssistant) -> None:
|
||||
assert info._filter_lifecycle_domains("light.test") is False
|
||||
|
||||
|
||||
def test_render_info_freeze_static(hass: HomeAssistant) -> None:
|
||||
def test_render_info_freeze_static(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo static freezing."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
info.domains.add("sensor")
|
||||
@@ -124,9 +125,8 @@ def test_render_info_freeze_static(hass: HomeAssistant) -> None:
|
||||
assert isinstance(info.entities, frozenset)
|
||||
|
||||
|
||||
def test_render_info_freeze(hass: HomeAssistant) -> None:
|
||||
def test_render_info_freeze(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo freezing with rate limits."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
|
||||
# Test all_states rate limit
|
||||
@@ -147,9 +147,8 @@ def test_render_info_freeze(hass: HomeAssistant) -> None:
|
||||
assert info.rate_limit == ALL_STATES_RATE_LIMIT
|
||||
|
||||
|
||||
def test_render_info_freeze_filters(hass: HomeAssistant) -> None:
|
||||
def test_render_info_freeze_filters(template_obj: template.Template) -> None:
|
||||
"""Test RenderInfo filter assignment during freeze."""
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
|
||||
# Test lifecycle filter assignment
|
||||
info = RenderInfo(template_obj)
|
||||
@@ -180,13 +179,12 @@ def test_render_info_freeze_filters(hass: HomeAssistant) -> None:
|
||||
assert info.filter is _false
|
||||
|
||||
|
||||
def test_render_info_context_var(hass: HomeAssistant) -> None:
|
||||
def test_render_info_context_var(template_obj: template.Template) -> None:
|
||||
"""Test render_info_cv context variable."""
|
||||
# Should start as None
|
||||
assert render_info_cv.get() is None
|
||||
|
||||
# Test setting and getting
|
||||
template_obj = template.Template("{{ 1 + 1 }}", hass)
|
||||
info = RenderInfo(template_obj)
|
||||
render_info_cv.set(info)
|
||||
assert render_info_cv.get() is info
|
||||
|
||||
Reference in New Issue
Block a user