2016-03-09 09:25:50 +00:00
""" Test Home Assistant template helper methods. """
2022-11-23 19:28:52 +00:00
from __future__ import annotations
from collections . abc import Iterable
2021-11-20 22:43:31 +00:00
from datetime import datetime , timedelta
2023-04-12 22:32:13 +00:00
import json
2021-11-20 22:43:31 +00:00
import logging
2017-11-28 05:29:01 +00:00
import math
2019-05-01 02:54:25 +00:00
import random
2022-11-23 19:28:52 +00:00
from typing import Any
2021-01-01 21:31:56 +00:00
from unittest . mock import patch
2016-02-21 04:58:01 +00:00
2021-11-24 14:51:43 +00:00
from freezegun import freeze_time
2023-04-12 22:32:13 +00:00
import orjson
2019-04-30 16:20:38 +00:00
import pytest
2020-10-27 21:51:58 +00:00
import voluptuous as vol
2019-04-30 16:20:38 +00:00
2016-02-21 19:13:40 +00:00
from homeassistant . components import group
2020-10-06 22:05:52 +00:00
from homeassistant . config import async_process_ha_core_config
2019-07-31 19:25:30 +00:00
from homeassistant . const import (
2020-09-21 21:03:39 +00:00
ATTR_UNIT_OF_MEASUREMENT ,
2022-06-24 21:28:26 +00:00
STATE_ON ,
2023-03-28 15:04:29 +00:00
STATE_UNAVAILABLE ,
2019-07-31 19:25:30 +00:00
VOLUME_LITERS ,
2023-08-03 19:12:01 +00:00
UnitOfLength ,
UnitOfMass ,
UnitOfPrecipitationDepth ,
2023-01-27 11:13:27 +00:00
UnitOfPressure ,
2023-01-27 09:58:55 +00:00
UnitOfSpeed ,
2023-08-03 19:12:01 +00:00
UnitOfTemperature ,
2019-07-31 19:25:30 +00:00
)
2021-12-21 16:25:07 +00:00
from homeassistant . core import HomeAssistant
2015-12-12 03:07:03 +00:00
from homeassistant . exceptions import TemplateError
2023-02-09 01:15:29 +00:00
from homeassistant . helpers import (
area_registry as ar ,
device_registry as dr ,
entity ,
entity_registry as er ,
template ,
)
2021-11-20 22:43:31 +00:00
from homeassistant . helpers . entity_platform import EntityPlatform
2022-06-25 16:19:11 +00:00
from homeassistant . helpers . json import json_dumps
2022-11-23 19:28:52 +00:00
from homeassistant . helpers . typing import TemplateVarsType
2020-09-30 14:13:53 +00:00
from homeassistant . setup import async_setup_component
2019-12-09 15:52:24 +00:00
import homeassistant . util . dt as dt_util
2016-08-09 03:42:25 +00:00
from homeassistant . util . unit_system import UnitSystem
2015-12-10 00:20:09 +00:00
2023-04-03 00:51:25 +00:00
from tests . common import MockConfigEntry , async_fire_time_changed
2021-02-20 05:50:59 +00:00
2016-02-14 23:08:23 +00:00
2022-11-23 19:28:52 +00:00
def _set_up_units ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Set up the tests. """
2019-07-31 19:25:30 +00:00
hass . config . units = UnitSystem (
2021-11-18 15:08:42 +00:00
" custom " ,
2023-08-03 19:12:01 +00:00
accumulated_precipitation = UnitOfPrecipitationDepth . MILLIMETERS ,
2022-10-25 10:51:23 +00:00
conversions = { } ,
2023-08-03 19:12:01 +00:00
length = UnitOfLength . METERS ,
mass = UnitOfMass . GRAMS ,
2023-01-27 11:13:27 +00:00
pressure = UnitOfPressure . PA ,
2023-08-03 19:12:01 +00:00
temperature = UnitOfTemperature . CELSIUS ,
2022-10-24 14:08:02 +00:00
volume = VOLUME_LITERS ,
2023-01-27 09:58:55 +00:00
wind_speed = UnitOfSpeed . KILOMETERS_PER_HOUR ,
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def render (
hass : HomeAssistant , template_str : str , variables : TemplateVarsType | None = None
) - > Any :
2021-09-29 18:16:02 +00:00
""" Create render info from template. """
tmp = template . Template ( template_str , hass )
return tmp . async_render ( variables )
2022-11-23 19:28:52 +00:00
def render_to_info (
hass : HomeAssistant , template_str : str , variables : TemplateVarsType | None = None
) - > template . RenderInfo :
2019-05-01 02:54:25 +00:00
""" Create render info from template. """
tmp = template . Template ( template_str , hass )
return tmp . async_render_to_info ( variables )
2022-11-23 19:28:52 +00:00
def extract_entities (
hass : HomeAssistant , template_str : str , variables : TemplateVarsType | None = None
) - > set [ str ] :
2019-05-01 02:54:25 +00:00
""" Extract entities from a template. """
info = render_to_info ( hass , template_str , variables )
2020-08-16 00:53:03 +00:00
return info . entities
2019-05-01 02:54:25 +00:00
2022-11-23 19:28:52 +00:00
def assert_result_info (
info : template . RenderInfo ,
result : Any ,
entities : Iterable [ str ] | None = None ,
domains : Iterable [ str ] | None = None ,
all_states : bool = False ,
) - > None :
2019-05-01 02:54:25 +00:00
""" Check result info. """
2020-09-02 08:35:15 +00:00
assert info . result ( ) == result
2020-08-16 00:53:03 +00:00
assert info . all_states == all_states
2020-09-26 21:29:49 +00:00
assert info . filter ( " invalid_entity_name.somewhere " ) == all_states
2019-05-01 02:54:25 +00:00
if entities is not None :
2020-08-16 00:53:03 +00:00
assert info . entities == frozenset ( entities )
2023-04-21 06:15:41 +00:00
assert all ( info . filter ( entity ) for entity in entities )
2020-09-26 21:29:49 +00:00
if not all_states :
assert not info . filter ( " invalid_entity_name.somewhere " )
2019-05-01 02:54:25 +00:00
else :
2020-08-16 00:53:03 +00:00
assert not info . entities
2019-05-01 02:54:25 +00:00
if domains is not None :
2020-08-16 00:53:03 +00:00
assert info . domains == frozenset ( domains )
2023-04-21 06:15:41 +00:00
assert all ( info . filter ( domain + " .entity " ) for domain in domains )
2019-05-01 02:54:25 +00:00
else :
2019-07-31 19:25:30 +00:00
assert not hasattr ( info , " _domains " )
2019-05-01 02:54:25 +00:00
2022-11-23 19:28:52 +00:00
def test_template_equality ( ) - > None :
2019-05-01 02:54:25 +00:00
""" Test template comparison and hashing. """
template_one = template . Template ( " {{ template_one }} " )
2020-01-03 13:47:06 +00:00
template_one_1 = template . Template ( " {{ template_one }} " )
2019-05-01 02:54:25 +00:00
template_two = template . Template ( " {{ template_two }} " )
assert template_one == template_one_1
assert template_one != template_two
assert hash ( template_one ) == hash ( template_one_1 )
assert hash ( template_one ) != hash ( template_two )
2023-04-04 05:38:15 +00:00
assert str ( template_one_1 ) == " Template<template=( {{ template_one }}) renders=0> "
2019-05-01 02:54:25 +00:00
with pytest . raises ( TypeError ) :
template . Template ( [ " {{ template_one }} " ] )
2022-11-23 19:28:52 +00:00
def test_invalid_template ( hass : HomeAssistant ) - > None :
2019-05-01 02:54:25 +00:00
""" Invalid template raises error. """
tmpl = template . Template ( " {{ " , hass )
with pytest . raises ( TemplateError ) :
tmpl . ensure_valid ( )
with pytest . raises ( TemplateError ) :
tmpl . async_render ( )
info = tmpl . async_render_to_info ( )
with pytest . raises ( TemplateError ) :
2020-09-02 08:35:15 +00:00
assert info . result ( ) == " impossible "
2019-05-01 02:54:25 +00:00
tmpl = template . Template ( " {{ states(keyword)}} " , hass )
tmpl . ensure_valid ( )
with pytest . raises ( TemplateError ) :
tmpl . async_render ( )
2022-11-23 19:28:52 +00:00
def test_referring_states_by_entity_id ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test referring states by entity id. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " happy " )
assert (
template . Template ( " {{ states.test.object.state }} " , hass ) . async_render ( )
== " happy "
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template ( ' {{ states[ " test.object " ].state }} ' , hass ) . async_render ( )
== " happy "
)
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template ( ' {{ states( " test.object " ) }} ' , hass ) . async_render ( ) == " happy "
)
2019-05-01 02:54:25 +00:00
2022-11-23 19:28:52 +00:00
def test_invalid_entity_id ( hass : HomeAssistant ) - > None :
2019-05-01 02:54:25 +00:00
""" Test referring states by entity id. """
with pytest . raises ( TemplateError ) :
2019-07-31 19:25:30 +00:00
template . Template ( ' {{ states[ " big.fat... " ] }} ' , hass ) . async_render ( )
2019-05-01 02:54:25 +00:00
with pytest . raises ( TemplateError ) :
2019-07-31 19:25:30 +00:00
template . Template ( ' {{ states.test[ " big.fat... " ] }} ' , hass ) . async_render ( )
2019-05-01 02:54:25 +00:00
with pytest . raises ( TemplateError ) :
2019-07-31 19:25:30 +00:00
template . Template ( ' {{ states[ " invalid/domain " ] }} ' , hass ) . async_render ( )
2019-05-01 02:54:25 +00:00
2022-11-23 19:28:52 +00:00
def test_raise_exception_on_error ( hass : HomeAssistant ) - > None :
2019-05-01 02:54:25 +00:00
""" Test raising an exception on error. """
with pytest . raises ( TemplateError ) :
2019-07-31 19:25:30 +00:00
template . Template ( " {{ invalid_syntax " ) . ensure_valid ( )
2019-05-01 02:54:25 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_iterating_all_states ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test iterating all states. """
2023-03-31 21:27:55 +00:00
tmpl_str = " { % f or state in states | sort(attribute= ' entity_id ' ) % } {{ state.state }} { % e ndfor % } "
2019-05-01 02:54:25 +00:00
info = render_to_info ( hass , tmpl_str )
2019-07-31 19:25:30 +00:00
assert_result_info ( info , " " , all_states = True )
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . ALL_STATES_RATE_LIMIT
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " happy " )
hass . states . async_set ( " sensor.temperature " , 10 )
2019-04-30 16:20:38 +00:00
2019-05-01 02:54:25 +00:00
info = render_to_info ( hass , tmpl_str )
2020-10-06 05:25:05 +00:00
assert_result_info ( info , " 10happy " , entities = [ ] , all_states = True )
2022-11-23 19:28:52 +00:00
def test_iterating_all_states_unavailable ( hass : HomeAssistant ) - > None :
2020-10-06 05:25:05 +00:00
""" Test iterating all states unavailable. """
hass . states . async_set ( " test.object " , " on " )
2023-01-26 00:23:53 +00:00
tmpl_str = (
" {{ "
" states "
" | selectattr( ' state ' , ' in ' , [ ' unavailable ' , ' unknown ' , ' none ' ]) "
" | list "
" | count "
" }} "
)
2020-10-06 05:25:05 +00:00
info = render_to_info ( hass , tmpl_str )
assert info . all_states is True
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . ALL_STATES_RATE_LIMIT
2020-10-06 05:25:05 +00:00
hass . states . async_set ( " test.object " , " unknown " )
hass . states . async_set ( " sensor.temperature " , 10 )
info = render_to_info ( hass , tmpl_str )
2020-10-06 22:05:52 +00:00
assert_result_info ( info , 1 , entities = [ ] , all_states = True )
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_iterating_domain_states ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test iterating domain states. """
2020-01-02 19:17:10 +00:00
tmpl_str = " { % f or state in states.sensor % } {{ state.state }} { % e ndfor % } "
2019-05-01 02:54:25 +00:00
info = render_to_info ( hass , tmpl_str )
2019-07-31 19:25:30 +00:00
assert_result_info ( info , " " , domains = [ " sensor " ] )
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . DOMAIN_STATES_RATE_LIMIT
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " happy " )
hass . states . async_set ( " sensor.back_door " , " open " )
hass . states . async_set ( " sensor.temperature " , 10 )
2015-12-10 00:20:09 +00:00
2019-05-01 02:54:25 +00:00
info = render_to_info ( hass , tmpl_str )
assert_result_info (
2019-07-31 19:25:30 +00:00
info ,
" open10 " ,
2020-10-06 05:25:05 +00:00
entities = [ ] ,
2019-07-31 19:25:30 +00:00
domains = [ " sensor " ] ,
)
2019-04-30 16:20:38 +00:00
2023-03-13 10:00:05 +00:00
async def test_import ( hass : HomeAssistant ) - > None :
2023-03-29 19:58:25 +00:00
""" Test that imports work from the config/custom_templates folder. """
await template . async_load_custom_templates ( hass )
2023-03-13 10:00:05 +00:00
assert " test.jinja " in template . _get_hass_loader ( hass ) . sources
assert " inner/inner_test.jinja " in template . _get_hass_loader ( hass ) . sources
assert (
template . Template (
"""
{ % import ' test.jinja ' as t % }
{ { t . test_macro ( ) } } { { t . test_variable } }
""" ,
hass ,
) . async_render ( )
== " macro variable "
)
assert (
template . Template (
"""
{ % import ' inner/inner_test.jinja ' as t % }
{ { t . test_macro ( ) } } { { t . test_variable } }
""" ,
hass ,
) . async_render ( )
== " inner macro inner variable "
)
with pytest . raises ( TemplateError ) :
template . Template (
"""
{ % import ' notfound.jinja ' as t % }
{ { t . test_macro ( ) } } { { t . test_variable } }
""" ,
hass ,
) . async_render ( )
async def test_import_change ( hass : HomeAssistant ) - > None :
""" Test that a change in HassLoader results in updated imports. """
2023-03-29 19:58:25 +00:00
await template . async_load_custom_templates ( hass )
2023-03-13 10:00:05 +00:00
to_test = template . Template (
"""
{ % import ' test.jinja ' as t % }
{ { t . test_macro ( ) } } { { t . test_variable } }
""" ,
hass ,
)
assert to_test . async_render ( ) == " macro variable "
template . _get_hass_loader ( hass ) . sources = {
" test.jinja " : """
{ % macro test_macro ( ) - % }
macro2
{ % - endmacro % }
{ % set test_variable = " variable2 " % }
"""
}
assert to_test . async_render ( ) == " macro2 variable2 "
2023-02-24 03:14:28 +00:00
def test_loop_controls ( hass : HomeAssistant ) - > None :
""" Test that loop controls are enabled. """
assert (
template . Template (
"""
{ % - for v in range ( 10 ) % }
{ % - if v == 1 - % }
{ % - continue - % }
{ % - elif v == 3 - % }
{ % - break - % }
{ % - endif - % }
{ { v } }
{ % - endfor - % }
""" ,
hass ,
) . async_render ( )
== " 02 "
)
2022-11-23 19:28:52 +00:00
def test_float_function ( hass : HomeAssistant ) - > None :
2021-09-29 18:16:02 +00:00
""" Test float function. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.temperature " , " 12 " )
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ float(states.sensor.temperature.state) }} " , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 12.0
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ float(states.sensor.temperature.state) > 11 }} " , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
is True
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
2019-07-31 19:25:30 +00:00
template . Template ( " {{ float( ' forgiving ' ) }} " , hass ) . async_render ( )
2019-05-01 02:54:25 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of default return value
2021-09-29 18:16:02 +00:00
assert render ( hass , " {{ float( ' bad ' , 1) }} " ) == 1
assert render ( hass , " {{ float( ' bad ' , default=1) }} " ) == 1
2022-11-23 19:28:52 +00:00
def test_float_filter ( hass : HomeAssistant ) - > None :
2021-09-29 18:16:02 +00:00
""" Test float filter. """
hass . states . async_set ( " sensor.temperature " , " 12 " )
assert render ( hass , " {{ states.sensor.temperature.state | float }} " ) == 12.0
assert render ( hass , " {{ states.sensor.temperature.state | float > 11 }} " ) is True
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
render ( hass , " {{ ' bad ' | float }} " )
# Test handling of default return value
2021-09-29 18:16:02 +00:00
assert render ( hass , " {{ ' bad ' | float(1) }} " ) == 1
assert render ( hass , " {{ ' bad ' | float(default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_int_filter ( hass : HomeAssistant ) - > None :
2021-10-11 22:12:42 +00:00
""" Test int filter. """
hass . states . async_set ( " sensor.temperature " , " 12.2 " )
assert render ( hass , " {{ states.sensor.temperature.state | int }} " ) == 12
assert render ( hass , " {{ states.sensor.temperature.state | int > 11 }} " ) is True
hass . states . async_set ( " sensor.temperature " , " 0x10 " )
assert render ( hass , " {{ states.sensor.temperature.state | int(base=16) }} " ) == 16
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
render ( hass , " {{ ' bad ' | int }} " )
# Test handling of default return value
2021-10-21 13:03:33 +00:00
assert render ( hass , " {{ ' bad ' | int(1) }} " ) == 1
2021-10-11 22:12:42 +00:00
assert render ( hass , " {{ ' bad ' | int(default=1) }} " ) == 1
2022-11-23 19:28:52 +00:00
def test_int_function ( hass : HomeAssistant ) - > None :
2021-10-11 22:12:42 +00:00
""" Test int filter. """
hass . states . async_set ( " sensor.temperature " , " 12.2 " )
assert render ( hass , " {{ int(states.sensor.temperature.state) }} " ) == 12
assert render ( hass , " {{ int(states.sensor.temperature.state) > 11 }} " ) is True
hass . states . async_set ( " sensor.temperature " , " 0x10 " )
assert render ( hass , " {{ int(states.sensor.temperature.state, base=16) }} " ) == 16
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
render ( hass , " {{ int( ' bad ' ) }} " )
# Test handling of default return value
2021-10-21 13:03:33 +00:00
assert render ( hass , " {{ int( ' bad ' , 1) }} " ) == 1
2021-10-11 22:12:42 +00:00
assert render ( hass , " {{ int( ' bad ' , default=1) }} " ) == 1
2022-11-23 19:28:52 +00:00
def test_bool_function ( hass : HomeAssistant ) - > None :
2022-06-28 14:22:09 +00:00
""" Test bool function. """
assert render ( hass , " {{ bool(true) }} " ) is True
assert render ( hass , " {{ bool(false) }} " ) is False
assert render ( hass , " {{ bool( ' on ' ) }} " ) is True
assert render ( hass , " {{ bool( ' off ' ) }} " ) is False
with pytest . raises ( TemplateError ) :
render ( hass , " {{ bool( ' unknown ' ) }} " )
with pytest . raises ( TemplateError ) :
render ( hass , " {{ bool(none) }} " )
assert render ( hass , " {{ bool( ' unavailable ' , none) }} " ) is None
assert render ( hass , " {{ bool( ' unavailable ' , default=none) }} " ) is None
2022-11-23 19:28:52 +00:00
def test_bool_filter ( hass : HomeAssistant ) - > None :
2022-06-28 14:22:09 +00:00
""" Test bool filter. """
assert render ( hass , " {{ true | bool }} " ) is True
assert render ( hass , " {{ false | bool }} " ) is False
assert render ( hass , " {{ ' on ' | bool }} " ) is True
assert render ( hass , " {{ ' off ' | bool }} " ) is False
with pytest . raises ( TemplateError ) :
render ( hass , " {{ ' unknown ' | bool }} " )
with pytest . raises ( TemplateError ) :
render ( hass , " {{ none | bool }} " )
assert render ( hass , " {{ ' unavailable ' | bool(none) }} " ) is None
assert render ( hass , " {{ ' unavailable ' | bool(default=none) }} " ) is None
2021-09-27 08:47:57 +00:00
@pytest.mark.parametrize (
2023-02-15 13:09:50 +00:00
( " value " , " expected " ) ,
2021-09-27 08:47:57 +00:00
[
( 0 , True ) ,
( 0.0 , True ) ,
( " 0 " , True ) ,
( " 0.0 " , True ) ,
( True , True ) ,
( False , True ) ,
( " True " , False ) ,
( " False " , False ) ,
( None , False ) ,
( " None " , False ) ,
( " horse " , False ) ,
( math . pi , True ) ,
( math . nan , False ) ,
( math . inf , False ) ,
( " nan " , False ) ,
( " inf " , False ) ,
] ,
)
2023-02-20 10:42:56 +00:00
def test_isnumber ( hass : HomeAssistant , value , expected ) - > None :
2021-09-27 08:47:57 +00:00
""" Test is_number. """
assert (
template . Template ( " {{ is_number(value) }} " , hass ) . async_render ( { " value " : value } )
== expected
)
assert (
template . Template ( " {{ value | is_number }} " , hass ) . async_render (
{ " value " : value }
)
== expected
)
2022-01-10 12:00:43 +00:00
assert (
template . Template ( " {{ value is is_number }} " , hass ) . async_render (
{ " value " : value }
)
== expected
)
2021-09-27 08:47:57 +00:00
2022-11-23 19:28:52 +00:00
def test_rounding_value ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test rounding value. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.temperature " , 12.78 )
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ states.sensor.temperature.state | round(1) }} " , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 12.8
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ states.sensor.temperature.state | multiply(10) | round }} " , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 128
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
' {{ states.sensor.temperature.state | round(1, " floor " ) }} ' , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 12.7
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
' {{ states.sensor.temperature.state | round(1, " ceil " ) }} ' , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 12.8
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2019-11-22 18:08:41 +00:00
assert (
template . Template (
' {{ states.sensor.temperature.state | round(1, " half " ) }} ' , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 13.0
2019-11-22 18:08:41 +00:00
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_rounding_value_on_error ( hass : HomeAssistant ) - > None :
2021-09-29 18:16:02 +00:00
""" Test rounding value handling of error. """
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ None | round }} " , hass ) . async_render ( )
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
with pytest . raises ( TemplateError ) :
2019-07-31 19:25:30 +00:00
template . Template ( ' {{ " no_number " | round }} ' , hass ) . async_render ( )
2019-04-30 16:20:38 +00:00
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | round(default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_multiply ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test multiply. """
2022-05-13 16:46:49 +00:00
tests = { 10 : 100 }
2019-04-30 16:20:38 +00:00
for inp , out in tests . items ( ) :
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ %s | multiply(10) | round }} " % inp , hass
) . async_render ( )
== out
)
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ abcd | multiply(10) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | multiply(10, 1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | multiply(10, default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_logarithm ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test logarithm. """
tests = [
2020-10-06 22:05:52 +00:00
( 4 , 2 , 2.0 ) ,
( 1000 , 10 , 3.0 ) ,
2022-05-13 16:46:49 +00:00
( math . e , " " , 1.0 ) , # The "" means the default base (e) will be used
2019-04-30 16:20:38 +00:00
]
for value , base , expected in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template (
2020-04-04 22:33:07 +00:00
f " {{ {{ { value } | log( { base } ) | round(1) }} }} " , hass
2019-07-31 19:25:30 +00:00
) . async_render ( )
== expected
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
2020-04-04 22:33:07 +00:00
f " {{ {{ log( { value } , { base } ) | round(1) }} }} " , hass
2019-07-31 19:25:30 +00:00
) . async_render ( )
== expected
)
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ invalid | log(_) }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ log(invalid, _) }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ 10 | log(invalid) }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ log(10, invalid) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | log(10, 1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | log(10, default=1) }} " ) == 1
assert render ( hass , " {{ log( ' no_number ' , 10, 1) }} " ) == 1
assert render ( hass , " {{ log( ' no_number ' , 10, default=1) }} " ) == 1
2022-06-03 13:27:10 +00:00
assert render ( hass , " {{ log(0, 10, 1) }} " ) == 1
assert render ( hass , " {{ log(0, 10, default=1) }} " ) == 1
2021-09-29 18:16:02 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_sine ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test sine. """
tests = [
2020-10-06 22:05:52 +00:00
( 0 , 0.0 ) ,
( math . pi / 2 , 1.0 ) ,
( math . pi , 0.0 ) ,
( math . pi * 1.5 , - 1.0 ) ,
( math . pi / 10 , 0.309 ) ,
2019-04-30 16:20:38 +00:00
]
for value , expected in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | sin | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ sin( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ ' duck ' | sin }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ invalid | sin( ' duck ' ) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | sin(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | sin(default=1) }} " ) == 1
assert render ( hass , " {{ sin( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ sin( ' no_number ' , default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_cos ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test cosine. """
tests = [
2020-10-06 22:05:52 +00:00
( 0 , 1.0 ) ,
( math . pi / 2 , 0.0 ) ,
( math . pi , - 1.0 ) ,
( math . pi * 1.5 , - 0.0 ) ,
( math . pi / 10 , 0.951 ) ,
2019-04-30 16:20:38 +00:00
]
for value , expected in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | cos | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ cos( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ ' error ' | cos }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ invalid | cos( ' error ' ) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
2022-05-13 16:46:49 +00:00
assert render ( hass , " {{ ' no_number ' | cos(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | cos(default=1) }} " ) == 1
assert render ( hass , " {{ cos( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ cos( ' no_number ' , default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_tan ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test tangent. """
tests = [
2020-10-06 22:05:52 +00:00
( 0 , 0.0 ) ,
( math . pi , - 0.0 ) ,
( math . pi / 180 * 45 , 1.0 ) ,
2020-11-13 12:22:29 +00:00
( math . pi / 180 * 90 , " 1.633123935319537e+16 " ) ,
2020-10-06 22:05:52 +00:00
( math . pi / 180 * 135 , - 1.0 ) ,
2019-04-30 16:20:38 +00:00
]
for value , expected in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | tan | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ tan( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ ' error ' | tan }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ invalid | tan( ' error ' ) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | tan(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | tan(default=1) }} " ) == 1
assert render ( hass , " {{ tan( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ tan( ' no_number ' , default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_sqrt ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test square root. """
tests = [
2020-10-06 22:05:52 +00:00
( 0 , 0.0 ) ,
( 1 , 1.0 ) ,
( 2 , 1.414 ) ,
( 10 , 3.162 ) ,
( 100 , 10.0 ) ,
2019-04-30 16:20:38 +00:00
]
for value , expected in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | sqrt | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ sqrt( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ ' error ' | sqrt }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ invalid | sqrt( ' error ' ) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | sqrt(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | sqrt(default=1) }} " ) == 1
assert render ( hass , " {{ sqrt( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ sqrt( ' no_number ' , default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_arc_sine ( hass : HomeAssistant ) - > None :
2019-08-09 18:16:47 +00:00
""" Test arcus sine. """
tests = [
2020-10-06 22:05:52 +00:00
( - 1.0 , - 1.571 ) ,
( - 0.5 , - 0.524 ) ,
( 0.0 , 0.0 ) ,
( 0.5 , 0.524 ) ,
( 1.0 , 1.571 ) ,
2019-08-09 18:16:47 +00:00
]
for value , expected in tests :
assert (
template . Template ( " {{ %s | asin | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ asin( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
invalid_tests = [
- 2.0 , # value error
2.0 , # value error
' " error " ' ,
]
for value in invalid_tests :
with pytest . raises ( TemplateError ) :
template . Template ( " {{ %s | asin | round(3) }} " % value , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
assert render ( hass , f " {{ {{ asin( { value } ) | round(3) }} }} " )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | asin(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | asin(default=1) }} " ) == 1
assert render ( hass , " {{ asin( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ asin( ' no_number ' , default=1) }} " ) == 1
2019-08-09 18:16:47 +00:00
2022-11-23 19:28:52 +00:00
def test_arc_cos ( hass : HomeAssistant ) - > None :
2019-08-09 18:16:47 +00:00
""" Test arcus cosine. """
tests = [
2020-10-06 22:05:52 +00:00
( - 1.0 , 3.142 ) ,
( - 0.5 , 2.094 ) ,
( 0.0 , 1.571 ) ,
( 0.5 , 1.047 ) ,
( 1.0 , 0.0 ) ,
2019-08-09 18:16:47 +00:00
]
for value , expected in tests :
assert (
template . Template ( " {{ %s | acos | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ acos( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
invalid_tests = [
- 2.0 , # value error
2.0 , # value error
' " error " ' ,
]
for value in invalid_tests :
with pytest . raises ( TemplateError ) :
template . Template ( " {{ %s | acos | round(3) }} " % value , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
assert render ( hass , f " {{ {{ acos( { value } ) | round(3) }} }} " )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | acos(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | acos(default=1) }} " ) == 1
assert render ( hass , " {{ acos( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ acos( ' no_number ' , default=1) }} " ) == 1
2019-08-09 18:16:47 +00:00
2022-11-23 19:28:52 +00:00
def test_arc_tan ( hass : HomeAssistant ) - > None :
2019-08-09 18:16:47 +00:00
""" Test arcus tangent. """
tests = [
2020-10-06 22:05:52 +00:00
( - 10.0 , - 1.471 ) ,
( - 2.0 , - 1.107 ) ,
( - 1.0 , - 0.785 ) ,
( - 0.5 , - 0.464 ) ,
( 0.0 , 0.0 ) ,
( 0.5 , 0.464 ) ,
( 1.0 , 0.785 ) ,
( 2.0 , 1.107 ) ,
( 10.0 , 1.471 ) ,
2019-08-09 18:16:47 +00:00
]
for value , expected in tests :
assert (
template . Template ( " {{ %s | atan | round(3) }} " % value , hass ) . async_render ( )
== expected
)
2021-09-29 18:16:02 +00:00
assert render ( hass , f " {{ {{ atan( { value } ) | round(3) }} }} " ) == expected
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ ' error ' | atan }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ invalid | atan( ' error ' ) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' no_number ' | atan(1) }} " ) == 1
assert render ( hass , " {{ ' no_number ' | atan(default=1) }} " ) == 1
assert render ( hass , " {{ atan( ' no_number ' , 1) }} " ) == 1
assert render ( hass , " {{ atan( ' no_number ' , default=1) }} " ) == 1
2019-08-09 18:16:47 +00:00
2022-11-23 19:28:52 +00:00
def test_arc_tan2 ( hass : HomeAssistant ) - > None :
2019-08-09 18:16:47 +00:00
""" Test two parameter version of arcus tangent. """
tests = [
2020-10-06 22:05:52 +00:00
( - 10.0 , - 10.0 , - 2.356 ) ,
( - 10.0 , 0.0 , - 1.571 ) ,
( - 10.0 , 10.0 , - 0.785 ) ,
( 0.0 , - 10.0 , 3.142 ) ,
( 0.0 , 0.0 , 0.0 ) ,
( 0.0 , 10.0 , 0.0 ) ,
( 10.0 , - 10.0 , 2.356 ) ,
( 10.0 , 0.0 , 1.571 ) ,
( 10.0 , 10.0 , 0.785 ) ,
( - 4.0 , 3.0 , - 0.927 ) ,
( - 1.0 , 2.0 , - 0.464 ) ,
( 2.0 , 1.0 , 1.107 ) ,
2019-08-09 18:16:47 +00:00
]
for y , x , expected in tests :
assert (
template . Template (
2020-04-04 22:33:07 +00:00
f " {{ {{ ( { y } , { x } ) | atan2 | round(3) }} }} " , hass
2019-08-09 18:16:47 +00:00
) . async_render ( )
== expected
)
assert (
template . Template (
2020-04-04 22:33:07 +00:00
f " {{ {{ atan2( { y } , { x } ) | round(3) }} }} " , hass
2019-08-09 18:16:47 +00:00
) . async_render ( )
== expected
)
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
with pytest . raises ( TemplateError ) :
template . Template ( " {{ ( ' duck ' , ' goose ' ) | atan2 }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ atan2( ' duck ' , ' goose ' ) }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ( ' duck ' , ' goose ' ) | atan2(1) }} " ) == 1
assert render ( hass , " {{ ( ' duck ' , ' goose ' ) | atan2(default=1) }} " ) == 1
assert render ( hass , " {{ atan2( ' duck ' , ' goose ' , 1) }} " ) == 1
assert render ( hass , " {{ atan2( ' duck ' , ' goose ' , default=1) }} " ) == 1
2019-08-09 18:16:47 +00:00
2022-11-23 19:28:52 +00:00
def test_strptime ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the parse timestamp method. """
tests = [
2019-07-31 19:25:30 +00:00
( " 2016-10-19 15:22:05.588122 UTC " , " % Y- % m- %d % H: % M: % S. %f % Z " , None ) ,
( " 2016-10-19 15:22:05.588122+0100 " , " % Y- % m- %d % H: % M: % S. %f % z " , None ) ,
( " 2016-10-19 15:22:05.588122 " , " % Y- % m- %d % H: % M: % S. %f " , None ) ,
( " 2016-10-19 " , " % Y- % m- %d " , None ) ,
( " 2016 " , " % Y " , None ) ,
( " 15:22:05 " , " % H: % M: % S " , None ) ,
2019-04-30 16:20:38 +00:00
]
for inp , fmt , expected in tests :
if expected is None :
2020-10-06 22:05:52 +00:00
expected = str ( datetime . strptime ( inp , fmt ) )
2019-04-30 16:20:38 +00:00
2020-04-04 22:33:07 +00:00
temp = f " {{ {{ strptime( ' { inp } ' , ' { fmt } ' ) }} }} "
2019-04-30 16:20:38 +00:00
2020-10-06 22:05:52 +00:00
assert template . Template ( temp , hass ) . async_render ( ) == expected
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
invalid_tests = [
( " 1469119144 " , " % Y " ) ,
( " invalid " , " % Y " ) ,
]
for inp , fmt in invalid_tests :
temp = f " {{ {{ strptime( ' { inp } ' , ' { fmt } ' ) }} }} "
with pytest . raises ( TemplateError ) :
template . Template ( temp , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ strptime( ' invalid ' , ' % Y ' , 1) }} " ) == 1
assert render ( hass , " {{ strptime( ' invalid ' , ' % Y ' , default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_timestamp_custom ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the timestamps to custom filter. """
2022-03-20 09:25:15 +00:00
hass . config . set_time_zone ( " UTC " )
2019-04-30 16:20:38 +00:00
now = dt_util . utcnow ( )
tests = [
2019-07-31 19:25:30 +00:00
( 1469119144 , None , True , " 2016-07-21 16:39:04 " ) ,
2020-10-06 22:05:52 +00:00
( 1469119144 , " % Y " , True , 2016 ) ,
2019-07-31 19:25:30 +00:00
( 1469119144 , " invalid " , True , " invalid " ) ,
( dt_util . as_timestamp ( now ) , None , False , now . strftime ( " % Y- % m- %d % H: % M: % S " ) ) ,
2019-04-30 16:20:38 +00:00
]
for inp , fmt , local , out in tests :
if fmt :
2020-01-03 13:47:06 +00:00
fil = f " timestamp_custom( ' { fmt } ' ) "
2019-04-30 16:20:38 +00:00
elif fmt and local :
2020-01-03 13:47:06 +00:00
fil = f " timestamp_custom( ' { fmt } ' , { local } ) "
2019-04-30 16:20:38 +00:00
else :
2019-07-31 19:25:30 +00:00
fil = " timestamp_custom "
2019-04-30 16:20:38 +00:00
2020-04-04 22:33:07 +00:00
assert template . Template ( f " {{ {{ { inp } | { fil } }} }} " , hass ) . async_render ( ) == out
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
invalid_tests = [
( None , None , None ) ,
]
for inp , fmt , local in invalid_tests :
if fmt :
fil = f " timestamp_custom( ' { fmt } ' ) "
elif fmt and local :
fil = f " timestamp_custom( ' { fmt } ' , { local } ) "
else :
fil = " timestamp_custom "
with pytest . raises ( TemplateError ) :
template . Template ( f " {{ {{ { inp } | { fil } }} }} " , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ None | timestamp_custom( ' invalid ' , True, 1) }} " ) == 1
assert render ( hass , " {{ None | timestamp_custom(default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_timestamp_local ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the timestamps to local filter. """
2022-03-20 09:25:15 +00:00
hass . config . set_time_zone ( " UTC " )
2022-05-13 16:46:49 +00:00
tests = [
( 1469119144 , " 2016-07-21T16:39:04+00:00 " ) ,
]
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
for inp , out in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | timestamp_local }} " % inp , hass ) . async_render ( )
== out
)
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
invalid_tests = [
None ,
]
for inp in invalid_tests :
with pytest . raises ( TemplateError ) :
template . Template ( " {{ %s | timestamp_local }} " % inp , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ None | timestamp_local(1) }} " ) == 1
assert render ( hass , " {{ None | timestamp_local(default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2021-06-07 13:02:15 +00:00
@pytest.mark.parametrize (
" input " ,
(
" 2021-06-03 13:00:00.000000+00:00 " ,
" 1986-07-09T12:00:00Z " ,
" 2016-10-19 15:22:05.588122+0100 " ,
" 2016-10-19 " ,
" 2021-01-01 00:00:01 " ,
" invalid " ,
) ,
)
2023-02-20 10:42:56 +00:00
def test_as_datetime ( hass : HomeAssistant , input ) - > None :
2021-06-07 13:02:15 +00:00
""" Test converting a timestamp string to a date object. """
expected = dt_util . parse_datetime ( input )
if expected is not None :
expected = str ( expected )
assert (
template . Template ( f " {{ {{ as_datetime( ' { input } ' ) }} }} " , hass ) . async_render ( )
== expected
)
assert (
template . Template ( f " {{ {{ ' { input } ' | as_datetime }} }} " , hass ) . async_render ( )
== expected
)
2022-11-23 19:28:52 +00:00
def test_as_datetime_from_timestamp ( hass : HomeAssistant ) - > None :
2021-11-24 08:51:56 +00:00
""" Test converting a UNIX timestamp to a date object. """
tests = [
( 1469119144 , " 2016-07-21 16:39:04+00:00 " ) ,
( 1469119144.0 , " 2016-07-21 16:39:04+00:00 " ) ,
( - 1 , " 1969-12-31 23:59:59+00:00 " ) ,
]
for input , output in tests :
# expected = dt_util.parse_datetime(input)
if output is not None :
output = str ( output )
assert (
template . Template ( f " {{ {{ as_datetime( { input } ) }} }} " , hass ) . async_render ( )
== output
)
assert (
template . Template ( f " {{ {{ { input } | as_datetime }} }} " , hass ) . async_render ( )
== output
)
assert (
template . Template ( f " {{ {{ as_datetime( ' { input } ' ) }} }} " , hass ) . async_render ( )
== output
)
assert (
template . Template ( f " {{ {{ ' { input } ' | as_datetime }} }} " , hass ) . async_render ( )
== output
)
2022-11-23 19:28:52 +00:00
def test_as_local ( hass : HomeAssistant ) - > None :
2020-09-03 19:35:16 +00:00
""" Test converting time to local. """
hass . states . async_set ( " test.object " , " available " )
last_updated = hass . states . get ( " test.object " ) . last_updated
assert template . Template (
" {{ as_local(states.test.object.last_updated) }} " , hass
) . async_render ( ) == str ( dt_util . as_local ( last_updated ) )
assert template . Template (
" {{ states.test.object.last_updated | as_local }} " , hass
) . async_render ( ) == str ( dt_util . as_local ( last_updated ) )
2022-11-23 19:28:52 +00:00
def test_to_json ( hass : HomeAssistant ) - > None :
2019-10-23 05:51:29 +00:00
""" Test the object to JSON string filter. """
# Note that we're not testing the actual json.loads and json.dumps methods,
# only the filters, so we don't need to be exhaustive with our sample JSON.
2020-10-06 22:05:52 +00:00
expected_result = { " Foo " : " Bar " }
2019-10-23 05:51:29 +00:00
actual_result = template . Template (
" {{ { ' Foo ' : ' Bar ' } | to_json }} " , hass
) . async_render ( )
assert actual_result == expected_result
2023-04-12 22:32:13 +00:00
expected_result = orjson . dumps ( { " Foo " : " Bar " } , option = orjson . OPT_INDENT_2 ) . decode ( )
actual_result = template . Template (
" {{ { ' Foo ' : ' Bar ' } | to_json(pretty_print=True) }} " , hass
) . async_render ( parse_result = False )
assert actual_result == expected_result
expected_result = orjson . dumps (
{ " Z " : 26 , " A " : 1 , " M " : 13 } , option = orjson . OPT_SORT_KEYS
) . decode ( )
actual_result = template . Template (
" {{ { ' Z ' : 26, ' A ' : 1, ' M ' : 13} | to_json(sort_keys=True) }} " , hass
) . async_render ( parse_result = False )
assert actual_result == expected_result
with pytest . raises ( TemplateError ) :
template . Template ( " {{ { ' Foo ' : now()} | to_json }} " , hass ) . async_render ( )
2019-10-23 05:51:29 +00:00
2023-04-12 22:32:13 +00:00
def test_to_json_ensure_ascii ( hass : HomeAssistant ) - > None :
2021-11-08 14:49:10 +00:00
""" Test the object to JSON string filter. """
# Note that we're not testing the actual json.loads and json.dumps methods,
# only the filters, so we don't need to be exhaustive with our sample JSON.
actual_value_ascii = template . Template (
2023-04-12 22:32:13 +00:00
" {{ ' Bar ҝ éèà ' | to_json(ensure_ascii=True) }} " , hass
2021-11-08 14:49:10 +00:00
) . async_render ( )
assert actual_value_ascii == ' " Bar \\ u049d \\ u00e9 \\ u00e8 \\ u00e0 " '
actual_value = template . Template (
" {{ ' Bar ҝ éèà ' | to_json(ensure_ascii=False) }} " , hass
) . async_render ( )
assert actual_value == ' " Bar ҝ éèà " '
2023-04-12 22:32:13 +00:00
expected_result = json . dumps ( { " Foo " : " Bar " } , indent = 2 )
actual_result = template . Template (
" {{ { ' Foo ' : ' Bar ' } | to_json(pretty_print=True, ensure_ascii=True) }} " , hass
) . async_render ( parse_result = False )
assert actual_result == expected_result
expected_result = json . dumps ( { " Z " : 26 , " A " : 1 , " M " : 13 } , sort_keys = True )
actual_result = template . Template (
" {{ { ' Z ' : 26, ' A ' : 1, ' M ' : 13} | to_json(sort_keys=True, ensure_ascii=True) }} " ,
hass ,
) . async_render ( parse_result = False )
assert actual_result == expected_result
2021-11-08 14:49:10 +00:00
2022-11-23 19:28:52 +00:00
def test_from_json ( hass : HomeAssistant ) - > None :
2019-10-23 05:51:29 +00:00
""" Test the JSON string to object filter. """
# Note that we're not testing the actual json.loads and json.dumps methods,
# only the filters, so we don't need to be exhaustive with our sample JSON.
expected_result = " Bar "
actual_result = template . Template (
' {{ ( \' { " Foo " : " Bar " } \' | from_json).Foo }} ' , hass
) . async_render ( )
assert actual_result == expected_result
2022-11-23 19:28:52 +00:00
def test_average ( hass : HomeAssistant ) - > None :
2021-10-26 20:43:45 +00:00
""" Test the average filter. """
assert template . Template ( " {{ [1, 2, 3] | average }} " , hass ) . async_render ( ) == 2
assert template . Template ( " {{ average([1, 2, 3]) }} " , hass ) . async_render ( ) == 2
assert template . Template ( " {{ average(1, 2, 3) }} " , hass ) . async_render ( ) == 2
2022-10-03 08:07:19 +00:00
# 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
)
2021-10-26 20:43:45 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ 1 | average }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ average() }} " , hass ) . async_render ( )
2022-10-03 08:07:19 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ average([]) }} " , hass ) . async_render ( )
2021-10-26 20:43:45 +00:00
2022-11-23 19:28:52 +00:00
def test_min ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the min filter. """
2020-10-06 22:05:52 +00:00
assert template . Template ( " {{ [1, 2, 3] | min }} " , hass ) . async_render ( ) == 1
2021-04-12 08:02:04 +00:00
assert template . Template ( " {{ min([1, 2, 3]) }} " , hass ) . async_render ( ) == 1
assert template . Template ( " {{ min(1, 2, 3) }} " , hass ) . async_render ( ) == 1
2019-04-30 16:20:38 +00:00
2022-01-04 09:07:23 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ 1 | min }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ min() }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ min(1) }} " , hass ) . async_render ( )
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_max ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the max filter. """
2020-10-06 22:05:52 +00:00
assert template . Template ( " {{ [1, 2, 3] | max }} " , hass ) . async_render ( ) == 3
2021-04-12 08:02:04 +00:00
assert template . Template ( " {{ max([1, 2, 3]) }} " , hass ) . async_render ( ) == 3
assert template . Template ( " {{ max(1, 2, 3) }} " , hass ) . async_render ( ) == 3
2019-04-30 16:20:38 +00:00
2022-01-04 09:07:23 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ 1 | max }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ max() }} " , hass ) . async_render ( )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ max(1) }} " , hass ) . async_render ( )
@pytest.mark.parametrize (
" attribute " ,
(
" a " ,
" b " ,
" c " ,
) ,
)
2023-02-20 10:42:56 +00:00
def test_min_max_attribute ( hass : HomeAssistant , attribute ) - > None :
2022-01-04 09:07:23 +00:00
""" Test the min and max filters with attribute. """
hass . states . async_set (
" test.object " ,
" test " ,
{
" objects " : [
{
" a " : 1 ,
" b " : 2 ,
" c " : 3 ,
} ,
{
" a " : 2 ,
" b " : 1 ,
" c " : 2 ,
} ,
{
" a " : 3 ,
" b " : 3 ,
" c " : 1 ,
} ,
] ,
} ,
)
assert (
template . Template (
2023-04-21 06:15:41 +00:00
f " {{ {{ (state_attr( ' test.object ' , ' objects ' ) | min(attribute= ' { attribute } ' ))[ ' { attribute } ' ] }} }} " ,
2022-01-04 09:07:23 +00:00
hass ,
) . async_render ( )
== 1
)
assert (
template . Template (
2023-04-21 06:15:41 +00:00
f " {{ {{ (min(state_attr( ' test.object ' , ' objects ' ), attribute= ' { attribute } ' ))[ ' { attribute } ' ] }} }} " ,
2022-01-04 09:07:23 +00:00
hass ,
) . async_render ( )
== 1
)
assert (
template . Template (
2023-04-21 06:15:41 +00:00
f " {{ {{ (state_attr( ' test.object ' , ' objects ' ) | max(attribute= ' { attribute } ' ))[ ' { attribute } ' ] }} }} " ,
2022-01-04 09:07:23 +00:00
hass ,
) . async_render ( )
== 3
)
assert (
template . Template (
2023-04-21 06:15:41 +00:00
f " {{ {{ (max(state_attr( ' test.object ' , ' objects ' ), attribute= ' { attribute } ' ))[ ' { attribute } ' ] }} }} " ,
2022-01-04 09:07:23 +00:00
hass ,
) . async_render ( )
== 3
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_ord ( hass : HomeAssistant ) - > None :
2019-07-25 22:06:51 +00:00
""" Test the ord filter. """
2020-10-06 22:05:52 +00:00
assert template . Template ( ' {{ " d " | ord }} ' , hass ) . async_render ( ) == 100
2019-07-25 22:06:51 +00:00
2022-11-23 19:28:52 +00:00
def test_base64_encode ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the base64_encode filter. """
2019-07-31 19:25:30 +00:00
assert (
template . Template ( ' {{ " homeassistant " | base64_encode }} ' , hass ) . async_render ( )
== " aG9tZWFzc2lzdGFudA== "
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_base64_decode ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the base64_decode filter. """
2019-07-31 19:25:30 +00:00
assert (
template . Template (
' {{ " aG9tZWFzc2lzdGFudA== " | base64_decode }} ' , hass
) . async_render ( )
== " homeassistant "
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_slugify ( hass : HomeAssistant ) - > None :
2021-12-21 10:35:54 +00:00
""" Test the slugify filter. """
assert (
template . Template ( ' {{ slugify( " Home Assistant " ) }} ' , hass ) . async_render ( )
== " home_assistant "
)
assert (
template . Template ( ' {{ " Home Assistant " | slugify }} ' , hass ) . async_render ( )
== " home_assistant "
)
assert (
template . Template ( ' {{ slugify( " Home Assistant " , " - " ) }} ' , hass ) . async_render ( )
== " home-assistant "
)
assert (
template . Template ( ' {{ " Home Assistant " | slugify( " - " ) }} ' , hass ) . async_render ( )
== " home-assistant "
)
2022-11-23 19:28:52 +00:00
def test_ordinal ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the ordinal filter. """
tests = [
2019-07-31 19:25:30 +00:00
( 1 , " 1st " ) ,
( 2 , " 2nd " ) ,
( 3 , " 3rd " ) ,
( 4 , " 4th " ) ,
( 5 , " 5th " ) ,
( 12 , " 12th " ) ,
( 100 , " 100th " ) ,
( 101 , " 101st " ) ,
2019-04-30 16:20:38 +00:00
]
for value , expected in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | ordinal }} " % value , hass ) . async_render ( )
== expected
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_timestamp_utc ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the timestamps to local filter. """
now = dt_util . utcnow ( )
2022-05-13 16:46:49 +00:00
tests = [
( 1469119144 , " 2016-07-21T16:39:04+00:00 " ) ,
( dt_util . as_timestamp ( now ) , now . isoformat ( ) ) ,
]
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
for inp , out in tests :
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ %s | timestamp_utc }} " % inp , hass ) . async_render ( )
== out
)
2019-04-30 16:20:38 +00:00
2022-05-13 16:46:49 +00:00
# Test handling of invalid input
invalid_tests = [
None ,
]
for inp in invalid_tests :
with pytest . raises ( TemplateError ) :
template . Template ( " {{ %s | timestamp_utc }} " % inp , hass ) . async_render ( )
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ None | timestamp_utc(1) }} " ) == 1
assert render ( hass , " {{ None | timestamp_utc(default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_as_timestamp ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test the as_timestamp function. """
2022-05-13 16:46:49 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( ' {{ as_timestamp( " invalid " ) }} ' , hass ) . async_render ( )
hass . states . async_set ( " test.object " , None )
with pytest . raises ( TemplateError ) :
template . Template ( " {{ as_timestamp(states.test.object) }} " , hass ) . async_render ( )
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
tpl = (
' {{ as_timestamp(strptime( " 2024-02-03T09:10:24+0000 " , '
2019-04-30 16:20:38 +00:00
' " % Y- % m- %d T % H: % M: % S % z " )) }} '
2019-07-31 19:25:30 +00:00
)
2020-10-06 22:05:52 +00:00
assert template . Template ( tpl , hass ) . async_render ( ) == 1706951424.0
2019-04-30 16:20:38 +00:00
2021-09-29 18:16:02 +00:00
# Test handling of default return value
assert render ( hass , " {{ ' invalid ' | as_timestamp(1) }} " ) == 1
assert render ( hass , " {{ ' invalid ' | as_timestamp(default=1) }} " ) == 1
assert render ( hass , " {{ as_timestamp( ' invalid ' , 1) }} " ) == 1
assert render ( hass , " {{ as_timestamp( ' invalid ' , default=1) }} " ) == 1
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
@patch.object ( random , " choice " )
2023-02-20 10:42:56 +00:00
def test_random_every_time ( test_choice , hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Ensure the random filter runs every time, not just once. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ [1,2] | random }} " , hass )
test_choice . return_value = " foo "
assert tpl . async_render ( ) == " foo "
test_choice . return_value = " bar "
assert tpl . async_render ( ) == " bar "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_passing_vars_as_keywords ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test passing variables as keywords. """
2020-10-06 22:05:52 +00:00
assert template . Template ( " {{ hello }} " , hass ) . async_render ( hello = 127 ) == 127
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_passing_vars_as_vars ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test passing variables as variables. """
2020-10-06 22:05:52 +00:00
assert template . Template ( " {{ hello }} " , hass ) . async_render ( { " hello " : 127 } ) == 127
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_passing_vars_as_list ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test passing variables as list. """
2020-10-06 22:05:52 +00:00
assert template . render_complex (
template . Template ( " {{ hello }} " , hass ) , { " hello " : [ " foo " , " bar " ] }
) == [ " foo " , " bar " ]
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_passing_vars_as_list_element ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test passing variables as list. """
2019-07-31 19:25:30 +00:00
assert (
template . render_complex (
template . Template ( " {{ hello[1] }} " , hass ) , { " hello " : [ " foo " , " bar " ] }
)
== " bar "
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_passing_vars_as_dict_element ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test passing variables as list. """
2019-07-31 19:25:30 +00:00
assert (
template . render_complex (
template . Template ( " {{ hello.foo }} " , hass ) , { " hello " : { " foo " : " bar " } }
)
== " bar "
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_passing_vars_as_dict ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test passing variables as list. """
2020-10-06 22:05:52 +00:00
assert template . render_complex (
template . Template ( " {{ hello }} " , hass ) , { " hello " : { " foo " : " bar " } }
) == { " foo " : " bar " }
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_with_valid_json ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with valid JSON. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ value_json.hello }} " , hass )
assert tpl . async_render_with_possible_json_value ( ' { " hello " : " world " } ' ) == " world "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_with_invalid_json ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with invalid JSON. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ value_json }} " , hass )
assert tpl . async_render_with_possible_json_value ( " { I AM NOT JSON } " ) == " "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_with_template_error_value (
hass : HomeAssistant ,
) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with template error value. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ non_existing.variable }} " , hass )
assert tpl . async_render_with_possible_json_value ( " hello " , " - " ) == " - "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_with_missing_json_value (
hass : HomeAssistant ,
) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with unknown JSON object. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ value_json.goodbye }} " , hass )
assert tpl . async_render_with_possible_json_value ( ' { " hello " : " world " } ' ) == " "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_valid_with_is_defined (
hass : HomeAssistant ,
) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with known JSON object. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ value_json.hello|is_defined }} " , hass )
assert tpl . async_render_with_possible_json_value ( ' { " hello " : " world " } ' ) == " world "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_undefined_json ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with unknown JSON object. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ value_json.bye|is_defined }} " , hass )
assert (
tpl . async_render_with_possible_json_value ( ' { " hello " : " world " } ' )
== ' { " hello " : " world " } '
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_undefined_json_error_value (
hass : HomeAssistant ,
) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with unknown JSON object. """
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ value_json.bye|is_defined }} " , hass )
assert tpl . async_render_with_possible_json_value ( ' { " hello " : " world " } ' , " " ) == " "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_render_with_possible_json_value_non_string_value ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Render with possible JSON value with non-string value. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2019-01-21 00:46:14 +00:00
{ { strptime ( value ~ ' +0000 ' , ' % Y- % m- %d % H: % M: % S % z ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2019-04-30 16:20:38 +00:00
value = datetime ( 2019 , 1 , 18 , 12 , 13 , 14 )
2021-05-08 05:46:26 +00:00
expected = str ( value . replace ( tzinfo = dt_util . UTC ) )
2019-04-30 16:20:38 +00:00
assert tpl . async_render_with_possible_json_value ( value ) == expected
2022-11-23 19:28:52 +00:00
def test_if_state_exists ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test if state exists works. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " available " )
2019-04-30 16:20:38 +00:00
tpl = template . Template (
2019-07-31 19:25:30 +00:00
" { % i f states.test.object % }exists { % e lse % }not exists { % e ndif % } " , hass
)
assert tpl . async_render ( ) == " exists "
2019-04-30 16:20:38 +00:00
2023-03-13 17:20:33 +00:00
def test_is_hidden_entity (
hass : HomeAssistant ,
entity_registry : er . EntityRegistry ,
) - > None :
""" Test is_hidden_entity method. """
hidden_entity = entity_registry . async_get_or_create (
" sensor " , " mock " , " hidden " , hidden_by = er . RegistryEntryHider . USER
)
visible_entity = entity_registry . async_get_or_create ( " sensor " , " mock " , " visible " )
assert template . Template (
f " {{ {{ is_hidden_entity( ' { hidden_entity . entity_id } ' ) }} }} " ,
hass ,
) . async_render ( )
assert not template . Template (
f " {{ {{ is_hidden_entity( ' { visible_entity . entity_id } ' ) }} }} " ,
hass ,
) . async_render ( )
2023-03-30 13:14:58 +00:00
assert not template . Template (
f " {{ {{ [ ' { visible_entity . entity_id } ' ] | select( ' is_hidden_entity ' ) | first }} }} " ,
hass ,
) . async_render ( )
2023-03-13 17:20:33 +00:00
2022-11-23 19:28:52 +00:00
def test_is_state ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test is_state method. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " available " )
tpl = template . Template (
"""
2016-02-14 21:07:21 +00:00
{ % if is_state ( " test.object " , " available " ) % } yes { % else % } no { % endif % }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
2015-12-13 06:19:37 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2017-04-16 23:36:15 +00:00
{ { is_state ( " test.noobject " , " available " ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is False
2017-04-16 23:36:15 +00:00
2022-10-25 17:49:51 +00:00
tpl = template . Template (
"""
{ % if " test.object " is is_state ( " available " ) % } yes { % else % } no { % endif % }
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
tpl = template . Template (
"""
{ { [ ' test.object ' ] | select ( " is_state " , " available " ) | first | default } }
""" ,
hass ,
)
assert tpl . async_render ( ) == " test.object "
2022-11-30 21:54:14 +00:00
tpl = template . Template (
"""
{ { is_state ( " test.object " , [ " on " , " off " , " available " ] ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) is True
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_is_state_attr ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test is_state_attr method. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " available " , { " mode " : " on " } )
tpl = template . Template (
"""
2016-02-14 21:07:21 +00:00
{ % if is_state_attr ( " test.object " , " mode " , " on " ) % } yes { % else % } no { % endif % }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
2015-12-31 20:58:18 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2017-04-16 23:36:15 +00:00
{ { is_state_attr ( " test.noobject " , " mode " , " on " ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is False
2019-04-30 16:20:38 +00:00
2022-10-25 17:49:51 +00:00
tpl = template . Template (
"""
{ % if " test.object " is is_state_attr ( " mode " , " on " ) % } yes { % else % } no { % endif % }
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
tpl = template . Template (
"""
{ { [ ' test.object ' ] | select ( " is_state_attr " , " mode " , " on " ) | first | default } }
""" ,
hass ,
)
assert tpl . async_render ( ) == " test.object "
2017-04-16 23:36:15 +00:00
2022-11-23 19:28:52 +00:00
def test_state_attr ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test state_attr method. """
2022-10-25 17:49:51 +00:00
hass . states . async_set (
" test.object " , " available " , { " effect " : " action " , " mode " : " on " }
)
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-03-28 07:04:18 +00:00
{ % if state_attr ( " test.object " , " mode " ) == " on " % } yes { % else % } no { % endif % }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
2018-03-28 07:04:18 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-03-28 07:04:18 +00:00
{ { state_attr ( " test.noobject " , " mode " ) == None } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2019-04-30 16:20:38 +00:00
2022-10-25 17:49:51 +00:00
tpl = template . Template (
"""
{ % if " test.object " | state_attr ( " mode " ) == " on " % } yes { % else % } no { % endif % }
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
tpl = template . Template (
"""
{ { [ ' test.object ' ] | map ( " state_attr " , " effect " ) | first | default } }
""" ,
hass ,
)
assert tpl . async_render ( ) == " action "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_states_function ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test using states as a function. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " available " )
2019-04-30 16:20:38 +00:00
tpl = template . Template ( ' {{ states( " test.object " ) }} ' , hass )
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " available "
2019-04-30 16:20:38 +00:00
tpl2 = template . Template ( ' {{ states( " test.object2 " ) }} ' , hass )
2019-07-31 19:25:30 +00:00
assert tpl2 . async_render ( ) == " unknown "
2019-04-30 16:20:38 +00:00
2022-10-25 17:49:51 +00:00
tpl = template . Template (
"""
{ % if " test.object " | states == " available " % } yes { % else % } no { % endif % }
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
tpl = template . Template (
"""
{ { [ ' test.object ' ] | map ( " states " ) | first | default } }
""" ,
hass ,
)
assert tpl . async_render ( ) == " available "
2019-04-30 16:20:38 +00:00
2023-05-04 09:25:35 +00:00
def test_has_value ( hass : HomeAssistant ) - > None :
2023-03-28 15:04:29 +00:00
""" Test has_value method. """
hass . states . async_set ( " test.value1 " , 1 )
hass . states . async_set ( " test.unavailable " , STATE_UNAVAILABLE )
tpl = template . Template (
"""
{ { has_value ( " test.value1 " ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) is True
tpl = template . Template (
"""
{ { has_value ( " test.unavailable " ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) is False
tpl = template . Template (
"""
{ { has_value ( " test.unknown " ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) is False
tpl = template . Template (
"""
{ % if " test.value1 " is has_value % } yes { % else % } no { % endif % }
""" ,
hass ,
)
assert tpl . async_render ( ) == " yes "
2019-07-31 19:25:30 +00:00
@patch (
2020-01-02 19:17:10 +00:00
" homeassistant.helpers.template.TemplateEnvironment.is_safe_callable " ,
2019-07-31 19:25:30 +00:00
return_value = True ,
)
2023-02-20 10:42:56 +00:00
def test_now ( mock_is_safe , hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test now method. """
now = dt_util . now ( )
2019-07-31 19:25:30 +00:00
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
2020-10-19 09:02:43 +00:00
info = template . Template ( " {{ now().isoformat() }} " , hass ) . async_render_to_info ( )
assert now . isoformat ( ) == info . result ( )
assert info . has_time is True
@patch (
" homeassistant.helpers.template.TemplateEnvironment.is_safe_callable " ,
return_value = True ,
)
2023-02-20 10:42:56 +00:00
def test_utcnow ( mock_is_safe , hass : HomeAssistant ) - > None :
2020-10-19 09:02:43 +00:00
""" Test now method. """
utcnow = dt_util . utcnow ( )
with patch ( " homeassistant.util.dt.utcnow " , return_value = utcnow ) :
info = template . Template (
" {{ utcnow().isoformat() }} " , hass
) . async_render_to_info ( )
assert utcnow . isoformat ( ) == info . result ( )
assert info . has_time is True
2019-04-30 16:20:38 +00:00
2021-11-24 14:51:43 +00:00
@pytest.mark.parametrize (
2023-02-15 13:09:50 +00:00
( " now " , " expected " , " expected_midnight " , " timezone_str " ) ,
2021-11-24 14:51:43 +00:00
[
# Host clock in UTC
(
" 2021-11-24 03:00:00+00:00 " ,
" 2021-11-23T10:00:00-08:00 " ,
" 2021-11-23T00:00:00-08:00 " ,
" America/Los_Angeles " ,
) ,
# Host clock in local time
(
" 2021-11-23 19:00:00-08:00 " ,
" 2021-11-23T10:00:00-08:00 " ,
" 2021-11-23T00:00:00-08:00 " ,
" America/Los_Angeles " ,
) ,
] ,
)
2021-10-22 17:51:22 +00:00
@patch (
" homeassistant.helpers.template.TemplateEnvironment.is_safe_callable " ,
return_value = True ,
)
2023-02-20 10:42:56 +00:00
def test_today_at (
mock_is_safe , hass : HomeAssistant , now , expected , expected_midnight , timezone_str
) - > None :
2021-10-22 17:51:22 +00:00
""" Test today_at method. """
2021-11-24 14:51:43 +00:00
freezer = freeze_time ( now )
freezer . start ( )
2021-10-22 17:51:22 +00:00
2022-03-20 09:25:15 +00:00
hass . config . set_time_zone ( timezone_str )
2021-10-22 17:51:22 +00:00
2021-11-24 14:51:43 +00:00
result = template . Template (
" {{ today_at( ' 10:00 ' ).isoformat() }} " ,
hass ,
) . async_render ( )
assert result == expected
result = template . Template (
" {{ today_at( ' 10:00:00 ' ).isoformat() }} " ,
hass ,
) . async_render ( )
assert result == expected
result = template . Template (
" {{ ( ' 10:00:00 ' | today_at).isoformat() }} " ,
hass ,
) . async_render ( )
assert result == expected
result = template . Template (
" {{ today_at().isoformat() }} " ,
hass ,
) . async_render ( )
assert result == expected_midnight
with pytest . raises ( TemplateError ) :
template . Template ( " {{ today_at( ' bad ' ) }} " , hass ) . async_render ( )
2021-10-22 17:51:22 +00:00
2023-03-28 13:10:28 +00:00
info = template . Template (
" {{ today_at( ' 10:00 ' ).isoformat() }} " , hass
) . async_render_to_info ( )
assert info . has_time is True
2021-11-24 14:51:43 +00:00
freezer . stop ( )
2021-10-22 17:51:22 +00:00
2020-04-20 17:29:12 +00:00
@patch (
" homeassistant.helpers.template.TemplateEnvironment.is_safe_callable " ,
return_value = True ,
)
2023-02-20 10:42:56 +00:00
def test_relative_time ( mock_is_safe , hass : HomeAssistant ) - > None :
2020-04-20 17:29:12 +00:00
""" Test relative_time method. """
2022-03-20 09:25:15 +00:00
hass . config . set_time_zone ( " UTC " )
2020-04-20 17:29:12 +00:00
now = datetime . strptime ( " 2000-01-01 10:00:00 +00:00 " , " % Y- % m- %d % H: % M: % S % z " )
2023-03-28 13:10:28 +00:00
relative_time_template = (
' {{ relative_time(strptime( " 2000-01-01 09:00:00 " , " % Y- % m- %d % H: % M: % S " ))}} '
)
2020-04-20 17:29:12 +00:00
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
2021-03-20 12:55:10 +00:00
result = template . Template (
2023-03-28 13:10:28 +00:00
relative_time_template ,
2021-03-20 12:55:10 +00:00
hass ,
) . async_render ( )
assert result == " 1 hour "
result = template . Template (
2023-01-26 00:23:53 +00:00
(
" {{ "
" relative_time( "
" strptime( "
' " 2000-01-01 09:00:00 +01:00 " , '
' " % Y- % m- %d % H: % M: % S % z " '
" ) "
" ) "
" }} "
) ,
2021-03-20 12:55:10 +00:00
hass ,
) . async_render ( )
assert result == " 2 hours "
result = template . Template (
2023-01-26 00:23:53 +00:00
(
" {{ "
" relative_time( "
" strptime( "
' " 2000-01-01 03:00:00 -06:00 " , '
' " % Y- % m- %d % H: % M: % S % z " '
" ) "
" ) "
" }} "
) ,
2021-03-20 12:55:10 +00:00
hass ,
) . async_render ( )
assert result == " 1 hour "
result1 = str (
template . strptime ( " 2000-01-01 11:00:00 +00:00 " , " % Y- % m- %d % H: % M: % S % z " )
2020-04-20 17:29:12 +00:00
)
2021-03-20 12:55:10 +00:00
result2 = template . Template (
2023-01-26 00:23:53 +00:00
(
" {{ "
" relative_time( "
" strptime( "
' " 2000-01-01 11:00:00 +00:00 " , '
' " % Y- % m- %d % H: % M: % S % z " '
" ) "
" ) "
" }} "
) ,
2021-03-20 12:55:10 +00:00
hass ,
) . async_render ( )
assert result1 == result2
result = template . Template (
' {{ relative_time( " string " )}} ' ,
hass ,
) . async_render ( )
assert result == " string "
2020-04-20 17:29:12 +00:00
2023-03-28 13:10:28 +00:00
info = template . Template ( relative_time_template , hass ) . async_render_to_info ( )
assert info . has_time is True
2020-04-20 17:29:12 +00:00
2020-09-11 20:07:31 +00:00
@patch (
" homeassistant.helpers.template.TemplateEnvironment.is_safe_callable " ,
return_value = True ,
)
2023-02-20 10:42:56 +00:00
def test_timedelta ( mock_is_safe , hass : HomeAssistant ) - > None :
2020-09-11 20:07:31 +00:00
""" Test relative_time method. """
now = datetime . strptime ( " 2000-01-01 10:00:00 +00:00 " , " % Y- % m- %d % H: % M: % S % z " )
with patch ( " homeassistant.util.dt.now " , return_value = now ) :
2021-03-20 12:55:10 +00:00
result = template . Template (
" {{ timedelta(seconds=120)}} " ,
hass ,
) . async_render ( )
assert result == " 0:02:00 "
result = template . Template (
" {{ timedelta(seconds=86400)}} " ,
hass ,
) . async_render ( )
assert result == " 1 day, 0:00:00 "
result = template . Template (
" {{ timedelta(days=1, hours=4)}} " , hass
) . async_render ( )
assert result == " 1 day, 4:00:00 "
result = template . Template (
" {{ relative_time(now() - timedelta(seconds=3600))}} " ,
hass ,
) . async_render ( )
assert result == " 1 hour "
result = template . Template (
" {{ relative_time(now() - timedelta(seconds=86400))}} " ,
hass ,
) . async_render ( )
assert result == " 1 day "
result = template . Template (
" {{ relative_time(now() - timedelta(seconds=86401))}} " ,
hass ,
) . async_render ( )
assert result == " 1 day "
result = template . Template (
" {{ relative_time(now() - timedelta(weeks=2, days=1))}} " ,
hass ,
) . async_render ( )
assert result == " 15 days "
2020-09-11 20:07:31 +00:00
2022-11-23 19:28:52 +00:00
def test_version ( hass : HomeAssistant ) - > None :
2022-09-15 13:01:40 +00:00
""" Test version filter and function. """
filter_result = template . Template (
" {{ ' 2099.9.9 ' | version}} " ,
hass ,
) . async_render ( )
function_result = template . Template (
" {{ version( ' 2099.9.9 ' )}} " ,
hass ,
) . async_render ( )
assert filter_result == function_result == " 2099.9.9 "
filter_result = template . Template (
" {{ ' 2099.9.9 ' | version < ' 2099.9.10 ' }} " ,
hass ,
) . async_render ( )
function_result = template . Template (
" {{ version( ' 2099.9.9 ' ) < ' 2099.9.10 ' }} " ,
hass ,
) . async_render ( )
assert filter_result == function_result is True
filter_result = template . Template (
" {{ ' 2099.9.9 ' | version == ' 2099.9.9 ' }} " ,
hass ,
) . async_render ( )
function_result = template . Template (
" {{ version( ' 2099.9.9 ' ) == ' 2099.9.9 ' }} " ,
hass ,
) . async_render ( )
assert filter_result == function_result is True
with pytest . raises ( TemplateError ) :
template . Template (
" {{ version(None) < ' 2099.9.10 ' }} " ,
hass ,
) . async_render ( )
2022-11-23 19:28:52 +00:00
def test_regex_match ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test regex_match method. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
r """
2018-08-20 14:34:18 +00:00
{ { ' 123-456-7890 ' | regex_match ( ' ( \\ d {3} )-( \\ d {3} )-( \\ d {4} ) ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2018-04-04 13:34:01 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { ' Home Assistant test ' | regex_match ( ' home ' , True ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { ' Another Home Assistant test ' | regex_match ( ' Home ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is False
2018-04-04 13:34:01 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { [ ' Home Assistant test ' ] | regex_match ( ' .*Assist ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2019-05-01 02:54:25 +00:00
2018-04-04 13:34:01 +00:00
2022-11-23 19:28:52 +00:00
def test_match_test ( hass : HomeAssistant ) - > None :
2021-04-15 18:13:27 +00:00
""" Test match test. """
tpl = template . Template (
r """
{ { ' 123-456-7890 ' is match ( ' ( \\ d {3} )-( \\ d {3} )-( \\ d {4} ) ' ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) is True
2022-11-23 19:28:52 +00:00
def test_regex_search ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test regex_search method. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
r """
2018-08-20 14:34:18 +00:00
{ { ' 123-456-7890 ' | regex_search ( ' ( \\ d {3} )-( \\ d {3} )-( \\ d {4} ) ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2018-04-04 13:34:01 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { ' Home Assistant test ' | regex_search ( ' home ' , True ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2018-04-04 13:34:01 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { ' Another Home Assistant test ' | regex_search ( ' Home ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2018-04-04 13:34:01 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { [ ' Home Assistant test ' ] | regex_search ( ' Assist ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is True
2019-05-01 02:54:25 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_search_test ( hass : HomeAssistant ) - > None :
2021-04-15 18:13:27 +00:00
""" Test search test. """
tpl = template . Template (
r """
{ { ' 123-456-7890 ' is search ( ' ( \\ d {3} )-( \\ d {3} )-( \\ d {4} ) ' ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) is True
2022-11-23 19:28:52 +00:00
def test_regex_replace ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test regex_replace method. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
r """
2018-08-20 14:34:18 +00:00
{ { ' Hello World ' | regex_replace ( ' (Hello \\ s) ' , ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " World "
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2020-01-05 12:09:17 +00:00
{ { [ ' Home hinderant test ' ] | regex_replace ( ' hinder ' , ' Assist ' ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == [ " Home Assistant test " ]
2019-05-01 02:54:25 +00:00
2018-04-04 13:34:01 +00:00
2022-11-23 19:28:52 +00:00
def test_regex_findall ( hass : HomeAssistant ) - > None :
2021-09-05 10:41:39 +00:00
""" Test regex_findall method. """
tpl = template . Template (
"""
{ { ' Flight from JFK to LHR ' | regex_findall ( ' ([A-Z] {3} ) ' ) } }
""" ,
hass ,
)
assert tpl . async_render ( ) == [ " JFK " , " LHR " ]
2022-11-23 19:28:52 +00:00
def test_regex_findall_index ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test regex_findall_index method. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-04-04 13:34:01 +00:00
{ { ' Flight from JFK to LHR ' | regex_findall_index ( ' ([A-Z] {3} ) ' , 0 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " JFK "
2018-04-04 13:34:01 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-04-04 13:34:01 +00:00
{ { ' Flight from JFK to LHR ' | regex_findall_index ( ' ([A-Z] {3} ) ' , 1 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " LHR "
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2019-05-01 02:54:25 +00:00
{ { [ ' JFK ' , ' LHR ' ] | regex_findall_index ( ' ([A-Z] {3} ) ' , 1 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
assert tpl . async_render ( ) == " LHR "
2019-05-01 02:54:25 +00:00
2018-04-04 13:34:01 +00:00
2022-11-23 19:28:52 +00:00
def test_bitwise_and ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test bitwise_and method. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-09-26 09:57:16 +00:00
{ { 8 | bitwise_and ( 8 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 8 & 8
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-09-26 09:57:16 +00:00
{ { 10 | bitwise_and ( 2 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 10 & 2
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-09-26 09:57:16 +00:00
{ { 8 | bitwise_and ( 2 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 8 & 2
2018-09-26 09:57:16 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_bitwise_or ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test bitwise_or method. """
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-09-26 09:57:16 +00:00
{ { 8 | bitwise_or ( 8 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 8 | 8
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-09-26 09:57:16 +00:00
{ { 10 | bitwise_or ( 2 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 10 | 2
2019-07-31 19:25:30 +00:00
tpl = template . Template (
"""
2018-09-26 09:57:16 +00:00
{ { 8 | bitwise_or ( 2 ) } }
2019-07-31 19:25:30 +00:00
""" ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 8 | 2
2019-04-30 16:20:38 +00:00
2023-02-20 10:42:56 +00:00
def test_pack ( hass : HomeAssistant , caplog : pytest . LogCaptureFixture ) - > None :
2021-12-03 07:58:15 +00:00
""" Test struct pack method. """
# render as filter
tpl = template . Template (
"""
{ { value | pack ( ' >I ' ) } }
""" ,
hass ,
)
variables = {
" value " : 0xDEADBEEF ,
}
assert tpl . async_render ( variables = variables ) == b " \xde \xad \xbe \xef "
# render as function
tpl = template . Template (
"""
{ { pack ( value , ' >I ' ) } }
""" ,
hass ,
)
variables = {
" value " : 0xDEADBEEF ,
}
assert tpl . async_render ( variables = variables ) == b " \xde \xad \xbe \xef "
# test with None value
tpl = template . Template (
"""
{ { pack ( value , ' >I ' ) } }
""" ,
hass ,
)
variables = {
" value " : None ,
}
# "Template warning: 'pack' unable to pack object with type '%s' and format_string '%s' see https://docs.python.org/3/library/struct.html for more information"
assert tpl . async_render ( variables = variables ) is None
assert (
2023-01-26 00:23:53 +00:00
" Template warning: ' pack ' unable to pack object ' None ' with type ' NoneType ' and "
" format_string ' >I ' see https://docs.python.org/3/library/struct.html for more "
" information " in caplog . text
2021-12-03 07:58:15 +00:00
)
# test with invalid filter
tpl = template . Template (
"""
{ { pack ( value , ' invalid filter ' ) } }
""" ,
hass ,
)
variables = {
" value " : 0xDEADBEEF ,
}
# "Template warning: 'pack' unable to pack object with type '%s' and format_string '%s' see https://docs.python.org/3/library/struct.html for more information"
assert tpl . async_render ( variables = variables ) is None
assert (
2023-01-26 00:23:53 +00:00
" Template warning: ' pack ' unable to pack object ' 3735928559 ' with type ' int ' "
" and format_string ' invalid filter ' see "
" https://docs.python.org/3/library/struct.html for more information "
2021-12-03 07:58:15 +00:00
in caplog . text
)
2023-02-20 10:42:56 +00:00
def test_unpack ( hass : HomeAssistant , caplog : pytest . LogCaptureFixture ) - > None :
2021-12-03 07:58:15 +00:00
""" Test struct unpack method. """
# render as filter
tpl = template . Template (
"""
{ { value | unpack ( ' >I ' ) } }
""" ,
hass ,
)
variables = {
" value " : b " \xde \xad \xbe \xef " ,
}
assert tpl . async_render ( variables = variables ) == 0xDEADBEEF
# render as function
tpl = template . Template (
"""
{ { unpack ( value , ' >I ' ) } }
""" ,
hass ,
)
variables = {
" value " : b " \xde \xad \xbe \xef " ,
}
assert tpl . async_render ( variables = variables ) == 0xDEADBEEF
# unpack with offset
tpl = template . Template (
"""
{ { unpack ( value , ' >H ' , offset = 2 ) } }
""" ,
hass ,
)
variables = {
" value " : b " \xde \xad \xbe \xef " ,
}
assert tpl . async_render ( variables = variables ) == 0xBEEF
# test with an empty bytes object
tpl = template . Template (
"""
{ { unpack ( value , ' >I ' ) } }
""" ,
hass ,
)
variables = {
" value " : b " " ,
}
assert tpl . async_render ( variables = variables ) is None
assert (
2023-01-26 00:23:53 +00:00
" Template warning: ' unpack ' unable to unpack object ' b ' ' ' with format_string "
" ' >I ' and offset 0 see https://docs.python.org/3/library/struct.html for more "
" information " in caplog . text
2021-12-03 07:58:15 +00:00
)
# test with invalid filter
tpl = template . Template (
"""
{ { unpack ( value , ' invalid filter ' ) } }
""" ,
hass ,
)
variables = {
" value " : b " " ,
}
assert tpl . async_render ( variables = variables ) is None
assert (
2023-01-26 00:23:53 +00:00
" Template warning: ' unpack ' unable to unpack object ' b ' ' ' with format_string "
" ' invalid filter ' and offset 0 see "
" https://docs.python.org/3/library/struct.html for more information "
2021-12-03 07:58:15 +00:00
in caplog . text
)
2022-11-23 19:28:52 +00:00
def test_distance_function_with_1_state ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 1 state. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test.object " , " happy " , { " latitude " : 32.87336 , " longitude " : - 117.22943 }
)
tpl = template . Template ( " {{ distance(states.test.object) | round }} " , hass )
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_with_2_states ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 2 states. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test.object " , " happy " , { " latitude " : 32.87336 , " longitude " : - 117.22943 }
)
hass . states . async_set (
" test.object_2 " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
tpl = template . Template (
2019-07-31 19:25:30 +00:00
" {{ distance(states.test.object, states.test.object_2) | round }} " , hass
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_with_1_coord ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 1 coord. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
tpl = template . Template ( ' {{ distance( " 32.87336 " , " -117.22943 " ) | round }} ' , hass )
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_with_2_coords ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 2 coords. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
assert (
template . Template (
2023-04-21 06:15:41 +00:00
f ' {{ {{ distance( " 32.87336 " , " -117.22943 " , { hass . config . latitude } , { hass . config . longitude } ) | round }} }} ' ,
2019-07-31 19:25:30 +00:00
hass ,
) . async_render ( )
2020-10-06 22:05:52 +00:00
== 187
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_with_1_state_1_coord ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 1 state 1 coord. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test.object_2 " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
tpl = template . Template (
2023-01-26 00:23:53 +00:00
' {{ distance( " 32.87336 " , " -117.22943 " , states.test.object_2) | round }} ' ,
2019-07-31 19:25:30 +00:00
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
tpl2 = template . Template (
2023-01-26 00:23:53 +00:00
' {{ distance(states.test.object_2, " 32.87336 " , " -117.22943 " ) | round }} ' ,
2019-07-31 19:25:30 +00:00
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl2 . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_return_none_if_invalid_state ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function return None if invalid state. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object_2 " , " happy " , { " latitude " : 10 } )
tpl = template . Template ( " {{ distance(states.test.object_2) | round }} " , hass )
2022-05-13 16:46:49 +00:00
with pytest . raises ( TemplateError ) :
tpl . async_render ( )
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_return_none_if_invalid_coord ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function return None if invalid coord. """
2019-07-31 19:25:30 +00:00
assert (
2020-10-06 22:05:52 +00:00
template . Template ( ' {{ distance( " 123 " , " abc " ) }} ' , hass ) . async_render ( ) is None
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2020-10-06 22:05:52 +00:00
assert template . Template ( ' {{ distance( " 123 " ) }} ' , hass ) . async_render ( ) is None
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test.object_2 " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
tpl = template . Template ( ' {{ distance( " 123 " , states.test_object_2) }} ' , hass )
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) is None
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_with_2_entity_ids ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 2 entity ids. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test.object " , " happy " , { " latitude " : 32.87336 , " longitude " : - 117.22943 }
)
hass . states . async_set (
" test.object_2 " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
tpl = template . Template (
2019-07-31 19:25:30 +00:00
' {{ distance( " test.object " , " test.object_2 " ) | round }} ' , hass
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_distance_function_with_1_entity_1_coord ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test distance function with 1 entity_id and 1 coord. """
_set_up_units ( hass )
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test.object " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
tpl = template . Template (
2019-07-31 19:25:30 +00:00
' {{ distance( " test.object " , " 32.87336 " , " -117.22943 " ) | round }} ' , hass
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 187
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_home_vs_domain ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function home vs domain. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.object " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" not_test_domain.but_closer " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ closest(states.test_domain).entity_id }} " , hass
) . async_render ( )
== " test_domain.object "
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
" {{ (states.test_domain | closest).entity_id }} " , hass
) . async_render ( )
== " test_domain.object "
)
2019-06-22 07:32:32 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_home_vs_all_states ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function home vs all states. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.object " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain_2.and_closer " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ closest(states).entity_id }} " , hass ) . async_render ( )
== " test_domain_2.and_closer "
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ (states | closest).entity_id }} " , hass ) . async_render ( )
== " test_domain_2.and_closer "
)
2019-06-22 07:32:32 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
async def test_closest_function_home_vs_group_entity_id ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function home vs group entity id. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.object " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" not_in_group.but_closer " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
2020-09-30 14:13:53 +00:00
assert await async_setup_component ( hass , " group " , { } )
await hass . async_block_till_done ( )
2019-07-31 19:25:30 +00:00
await group . Group . async_create_group ( hass , " location group " , [ " test_domain.object " ] )
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
info = render_to_info ( hass , ' {{ closest( " group.location_group " ).entity_id }} ' )
assert_result_info (
2020-08-16 00:53:03 +00:00
info , " test_domain.object " , { " group.location_group " , " test_domain.object " }
2019-07-31 19:25:30 +00:00
)
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
async def test_closest_function_home_vs_group_state ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function home vs group state. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.object " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" not_in_group.but_closer " ,
" happy " ,
{ " latitude " : hass . config . latitude , " longitude " : hass . config . longitude } ,
)
2019-04-30 16:20:38 +00:00
2020-09-30 14:13:53 +00:00
assert await async_setup_component ( hass , " group " , { } )
await hass . async_block_till_done ( )
2019-07-31 19:25:30 +00:00
await group . Group . async_create_group ( hass , " location group " , [ " test_domain.object " ] )
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
info = render_to_info ( hass , ' {{ closest( " group.location_group " ).entity_id }} ' )
2019-05-01 02:54:25 +00:00
assert_result_info (
2020-08-16 00:53:03 +00:00
info , " test_domain.object " , { " group.location_group " , " test_domain.object " }
2019-07-31 19:25:30 +00:00
)
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
info = render_to_info ( hass , " {{ closest(states.group.location_group).entity_id }} " )
2019-05-01 02:54:25 +00:00
assert_result_info (
2020-08-16 00:53:03 +00:00
info , " test_domain.object " , { " test_domain.object " , " group.location_group " }
2019-07-31 19:25:30 +00:00
)
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
async def test_expand ( hass : HomeAssistant ) - > None :
2019-06-22 07:32:32 +00:00
""" Test expand function. """
2019-07-31 19:25:30 +00:00
info = render_to_info ( hass , " {{ expand( ' test.object ' ) }} " )
2020-10-06 22:05:52 +00:00
assert_result_info ( info , [ ] , [ " test.object " ] )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-06-22 07:32:32 +00:00
2019-07-31 19:25:30 +00:00
info = render_to_info ( hass , " {{ expand(56) }} " )
2020-10-06 22:05:52 +00:00
assert_result_info ( info , [ ] )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-06-22 07:32:32 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " test.object " , " happy " )
2019-06-22 07:32:32 +00:00
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand( ' test.object ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2019-07-31 19:25:30 +00:00
)
2020-08-16 00:53:03 +00:00
assert_result_info ( info , " test.object " , [ " test.object " ] )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-06-22 07:32:32 +00:00
info = render_to_info (
2019-07-31 19:25:30 +00:00
hass ,
2023-03-31 21:27:55 +00:00
" {{ expand( ' group.new_group ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2019-07-31 19:25:30 +00:00
)
assert_result_info ( info , " " , [ " group.new_group " ] )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-06-22 07:32:32 +00:00
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand(states.group) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2019-07-31 19:25:30 +00:00
)
assert_result_info ( info , " " , [ ] , [ " group " ] )
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . DOMAIN_STATES_RATE_LIMIT
2019-06-22 07:32:32 +00:00
2020-09-30 14:13:53 +00:00
assert await async_setup_component ( hass , " group " , { } )
await hass . async_block_till_done ( )
2019-07-31 19:25:30 +00:00
await group . Group . async_create_group ( hass , " new group " , [ " test.object " ] )
2019-06-22 07:32:32 +00:00
info = render_to_info (
2019-07-31 19:25:30 +00:00
hass ,
2023-03-31 21:27:55 +00:00
" {{ expand( ' group.new_group ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2019-07-31 19:25:30 +00:00
)
2020-08-16 00:53:03 +00:00
assert_result_info ( info , " test.object " , { " group.new_group " , " test.object " } )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-06-22 07:32:32 +00:00
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand(states.group) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2019-07-31 19:25:30 +00:00
)
2020-10-06 05:25:05 +00:00
assert_result_info ( info , " test.object " , { " test.object " } , [ " group " ] )
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . DOMAIN_STATES_RATE_LIMIT
2019-06-22 07:32:32 +00:00
info = render_to_info (
2019-07-31 19:25:30 +00:00
hass ,
2023-01-26 00:23:53 +00:00
(
" {{ expand( ' group.new_group ' , ' test.object ' ) "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} "
2023-01-26 00:23:53 +00:00
) ,
2019-07-31 19:25:30 +00:00
)
2020-08-16 00:53:03 +00:00
assert_result_info ( info , " test.object " , { " test.object " , " group.new_group " } )
2019-06-22 07:32:32 +00:00
info = render_to_info (
2019-07-31 19:25:30 +00:00
hass ,
2023-01-26 00:23:53 +00:00
(
" {{ [ ' group.new_group ' , ' test.object ' ] | expand "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} "
2023-01-26 00:23:53 +00:00
) ,
2019-07-31 19:25:30 +00:00
)
2020-08-16 00:53:03 +00:00
assert_result_info ( info , " test.object " , { " test.object " , " group.new_group " } )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2020-08-16 00:53:03 +00:00
hass . states . async_set ( " sensor.power_1 " , 0 )
hass . states . async_set ( " sensor.power_2 " , 200.2 )
hass . states . async_set ( " sensor.power_3 " , 400.4 )
2020-09-30 14:13:53 +00:00
assert await async_setup_component ( hass , " group " , { } )
await hass . async_block_till_done ( )
2020-08-16 00:53:03 +00:00
await group . Group . async_create_group (
hass , " power sensors " , [ " sensor.power_1 " , " sensor.power_2 " , " sensor.power_3 " ]
)
info = render_to_info (
hass ,
2023-01-26 00:23:53 +00:00
(
" {{ states.group.power_sensors.attributes.entity_id | expand "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' state ' )|map( ' float ' )|sum }} "
2023-01-26 00:23:53 +00:00
) ,
2020-08-16 00:53:03 +00:00
)
assert_result_info (
info ,
2020-10-06 22:05:52 +00:00
200.2 + 400.4 ,
2020-08-16 00:53:03 +00:00
{ " group.power_sensors " , " sensor.power_1 " , " sensor.power_2 " , " sensor.power_3 " } ,
)
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2019-06-22 07:32:32 +00:00
2022-03-30 08:11:09 +00:00
# With group entities
hass . states . async_set ( " light.first " , " on " )
hass . states . async_set ( " light.second " , " off " )
assert await async_setup_component (
hass ,
" light " ,
{
" light " : {
" platform " : " group " ,
" name " : " Grouped " ,
" entities " : [ " light.first " , " light.second " ] ,
}
} ,
)
await hass . async_block_till_done ( )
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand( ' light.grouped ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2022-03-30 08:11:09 +00:00
)
assert_result_info (
info ,
" light.first, light.second " ,
[ " light.grouped " , " light.first " , " light.second " ] ,
)
2022-04-11 10:59:45 +00:00
assert await async_setup_component (
hass ,
" zone " ,
{
" zone " : {
" name " : " Test " ,
" latitude " : 32.880837 ,
" longitude " : - 117.237561 ,
" radius " : 250 ,
" passive " : False ,
}
} ,
)
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand( ' zone.test ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2022-04-11 10:59:45 +00:00
)
assert_result_info (
info ,
" " ,
[ " zone.test " ] ,
)
hass . states . async_set (
" person.person1 " ,
" test " ,
)
await hass . async_block_till_done ( )
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand( ' zone.test ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2022-04-11 10:59:45 +00:00
)
assert_result_info (
info ,
" person.person1 " ,
[ " zone.test " , " person.person1 " ] ,
)
hass . states . async_set (
" person.person2 " ,
" test " ,
)
await hass . async_block_till_done ( )
info = render_to_info (
2023-03-31 21:27:55 +00:00
hass ,
" {{ expand( ' zone.test ' ) | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} " ,
2022-04-11 10:59:45 +00:00
)
assert_result_info (
info ,
" person.person1, person.person2 " ,
[ " zone.test " , " person.person1 " , " person.person2 " ] ,
)
2019-06-22 07:32:32 +00:00
2023-02-09 01:15:29 +00:00
async def test_device_entities (
hass : HomeAssistant ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2021-08-25 19:16:51 +00:00
""" Test device_entities function. """
2021-02-20 05:50:59 +00:00
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-02-20 05:50:59 +00:00
# Test non existing device ids
info = render_to_info ( hass , " {{ device_entities( ' abc123 ' ) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
info = render_to_info ( hass , " {{ device_entities(56) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
# Test device without entities
device_entry = device_registry . async_get_or_create (
config_entry_id = config_entry . entry_id ,
2021-04-30 21:58:50 +00:00
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
2021-02-20 05:50:59 +00:00
)
info = render_to_info ( hass , f " {{ {{ device_entities( ' { device_entry . id } ' ) }} }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
# Test device with single entity, which has no state
entity_registry . async_get_or_create (
" light " ,
" hue " ,
" 5678 " ,
config_entry = config_entry ,
device_id = device_entry . id ,
)
info = render_to_info ( hass , f " {{ {{ device_entities( ' { device_entry . id } ' ) }} }} " )
assert_result_info ( info , [ " light.hue_5678 " ] , [ ] )
assert info . rate_limit is None
info = render_to_info (
hass ,
2023-01-26 00:23:53 +00:00
(
f " {{ {{ device_entities( ' { device_entry . id } ' ) | expand "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} "
2023-01-26 00:23:53 +00:00
) ,
2021-02-20 05:50:59 +00:00
)
assert_result_info ( info , " " , [ " light.hue_5678 " ] )
assert info . rate_limit is None
# Test device with single entity, with state
hass . states . async_set ( " light.hue_5678 " , " happy " )
info = render_to_info (
hass ,
2023-01-26 00:23:53 +00:00
(
f " {{ {{ device_entities( ' { device_entry . id } ' ) | expand "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} "
2023-01-26 00:23:53 +00:00
) ,
2021-02-20 05:50:59 +00:00
)
assert_result_info ( info , " light.hue_5678 " , [ " light.hue_5678 " ] )
assert info . rate_limit is None
# Test device with multiple entities, which have a state
entity_registry . async_get_or_create (
" light " ,
" hue " ,
" ABCD " ,
config_entry = config_entry ,
device_id = device_entry . id ,
)
hass . states . async_set ( " light.hue_abcd " , " camper " )
info = render_to_info ( hass , f " {{ {{ device_entities( ' { device_entry . id } ' ) }} }} " )
assert_result_info ( info , [ " light.hue_5678 " , " light.hue_abcd " ] , [ ] )
assert info . rate_limit is None
info = render_to_info (
hass ,
2023-01-26 00:23:53 +00:00
(
f " {{ {{ device_entities( ' { device_entry . id } ' ) | expand "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | join( ' , ' ) }} "
2023-01-26 00:23:53 +00:00
) ,
2021-02-20 05:50:59 +00:00
)
assert_result_info (
info , " light.hue_5678, light.hue_abcd " , [ " light.hue_5678 " , " light.hue_abcd " ]
)
assert info . rate_limit is None
2023-02-09 01:15:29 +00:00
async def test_integration_entities (
hass : HomeAssistant , entity_registry : er . EntityRegistry
) - > None :
2021-11-20 22:43:31 +00:00
""" Test integration_entities function. """
# test entities for given config entry title
config_entry = MockConfigEntry ( domain = " mock " , title = " Mock bridge 2 " )
config_entry . add_to_hass ( hass )
entity_entry = entity_registry . async_get_or_create (
" sensor " , " mock " , " test " , config_entry = config_entry
)
info = render_to_info ( hass , " {{ integration_entities( ' Mock bridge 2 ' ) }} " )
assert_result_info ( info , [ entity_entry . entity_id ] )
assert info . rate_limit is None
# test integration entities not in entity registry
mock_entity = entity . Entity ( )
mock_entity . hass = hass
mock_entity . entity_id = " light.test_entity "
mock_entity . platform = EntityPlatform (
hass = hass ,
logger = logging . getLogger ( __name__ ) ,
domain = " light " ,
platform_name = " entryless_integration " ,
platform = None ,
scan_interval = timedelta ( seconds = 30 ) ,
entity_namespace = None ,
)
await mock_entity . async_internal_added_to_hass ( )
info = render_to_info ( hass , " {{ integration_entities( ' entryless_integration ' ) }} " )
assert_result_info ( info , [ " light.test_entity " ] )
assert info . rate_limit is None
# Test non existing integration/entry title
info = render_to_info ( hass , " {{ integration_entities( ' abc123 ' ) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
2023-02-09 01:15:29 +00:00
async def test_config_entry_id (
hass : HomeAssistant , entity_registry : er . EntityRegistry
) - > None :
2022-10-25 10:11:14 +00:00
""" Test config_entry_id function. """
2022-09-29 10:41:59 +00:00
config_entry = MockConfigEntry ( domain = " light " , title = " Some integration " )
config_entry . add_to_hass ( hass )
entity_entry = entity_registry . async_get_or_create (
" sensor " , " test " , " test " , suggested_object_id = " test " , config_entry = config_entry
)
2022-10-25 10:11:14 +00:00
info = render_to_info ( hass , " {{ ' sensor.fail ' | config_entry_id }} " )
2022-09-29 10:41:59 +00:00
assert_result_info ( info , None )
assert info . rate_limit is None
2022-10-25 10:11:14 +00:00
info = render_to_info ( hass , " {{ 56 | config_entry_id }} " )
2022-09-29 10:41:59 +00:00
assert_result_info ( info , None )
2022-10-25 10:11:14 +00:00
info = render_to_info ( hass , " {{ ' not_a_real_entity_id ' | config_entry_id }} " )
2022-09-29 10:41:59 +00:00
assert_result_info ( info , None )
2022-10-25 10:11:14 +00:00
info = render_to_info (
hass , f " {{ {{ config_entry_id( ' { entity_entry . entity_id } ' ) }} }} "
)
2022-09-29 10:41:59 +00:00
assert_result_info ( info , config_entry . entry_id )
assert info . rate_limit is None
2023-02-09 01:15:29 +00:00
async def test_device_id (
hass : HomeAssistant ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2021-07-27 22:55:55 +00:00
""" Test device_id function. """
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-07-27 22:55:55 +00:00
device_entry = device_registry . async_get_or_create (
config_entry_id = config_entry . entry_id ,
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
model = " test " ,
2021-08-31 12:56:47 +00:00
name = " test " ,
2021-07-27 22:55:55 +00:00
)
entity_entry = entity_registry . async_get_or_create (
" sensor " , " test " , " test " , suggested_object_id = " test " , device_id = device_entry . id
)
entity_entry_no_device = entity_registry . async_get_or_create (
" sensor " , " test " , " test_no_device " , suggested_object_id = " test "
)
info = render_to_info ( hass , " {{ ' sensor.fail ' | device_id }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
2021-08-31 12:56:47 +00:00
info = render_to_info ( hass , " {{ 56 | device_id }} " )
assert_result_info ( info , None )
2021-07-27 22:55:55 +00:00
2021-08-31 12:56:47 +00:00
info = render_to_info ( hass , " {{ ' not_a_real_entity_id ' | device_id }} " )
assert_result_info ( info , None )
2021-07-27 22:55:55 +00:00
info = render_to_info (
hass , f " {{ {{ device_id( ' { entity_entry_no_device . entity_id } ' ) }} }} "
)
assert_result_info ( info , None )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ device_id( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , device_entry . id )
assert info . rate_limit is None
2021-08-31 12:56:47 +00:00
info = render_to_info ( hass , " {{ device_id( ' test ' ) }} " )
assert_result_info ( info , device_entry . id )
assert info . rate_limit is None
2021-07-27 22:55:55 +00:00
2023-02-09 01:15:29 +00:00
async def test_device_attr (
hass : HomeAssistant ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2021-07-27 22:55:55 +00:00
""" Test device_attr and is_device_attr functions. """
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-07-27 22:55:55 +00:00
# Test non existing device ids (device_attr)
info = render_to_info ( hass , " {{ device_attr( ' abc123 ' , ' id ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
with pytest . raises ( TemplateError ) :
info = render_to_info ( hass , " {{ device_attr(56, ' id ' ) }} " )
assert_result_info ( info , None )
# Test non existing device ids (is_device_attr)
info = render_to_info ( hass , " {{ is_device_attr( ' abc123 ' , ' id ' , ' test ' ) }} " )
assert_result_info ( info , False )
assert info . rate_limit is None
with pytest . raises ( TemplateError ) :
info = render_to_info ( hass , " {{ is_device_attr(56, ' id ' , ' test ' ) }} " )
assert_result_info ( info , False )
# Test non existing entity id (device_attr)
info = render_to_info ( hass , " {{ device_attr( ' entity.test ' , ' id ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test non existing entity id (is_device_attr)
info = render_to_info ( hass , " {{ is_device_attr( ' entity.test ' , ' id ' , ' test ' ) }} " )
assert_result_info ( info , False )
assert info . rate_limit is None
device_entry = device_registry . async_get_or_create (
config_entry_id = config_entry . entry_id ,
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
model = " test " ,
)
entity_entry = entity_registry . async_get_or_create (
" sensor " , " test " , " test " , suggested_object_id = " test " , device_id = device_entry . id
)
# Test non existent device attribute (device_attr)
info = render_to_info (
hass , f " {{ {{ device_attr( ' { device_entry . id } ' , ' invalid_attr ' ) }} }} "
)
assert_result_info ( info , None )
assert info . rate_limit is None
# Test non existent device attribute (is_device_attr)
info = render_to_info (
hass , f " {{ {{ is_device_attr( ' { device_entry . id } ' , ' invalid_attr ' , ' test ' ) }} }} "
)
assert_result_info ( info , False )
assert info . rate_limit is None
# Test None device attribute (device_attr)
info = render_to_info (
hass , f " {{ {{ device_attr( ' { device_entry . id } ' , ' manufacturer ' ) }} }} "
)
assert_result_info ( info , None )
assert info . rate_limit is None
# Test None device attribute mismatch (is_device_attr)
info = render_to_info (
hass , f " {{ {{ is_device_attr( ' { device_entry . id } ' , ' manufacturer ' , ' test ' ) }} }} "
)
assert_result_info ( info , False )
assert info . rate_limit is None
# Test None device attribute match (is_device_attr)
info = render_to_info (
hass , f " {{ {{ is_device_attr( ' { device_entry . id } ' , ' manufacturer ' , None) }} }} "
)
assert_result_info ( info , True )
assert info . rate_limit is None
# Test valid device attribute match (device_attr)
info = render_to_info ( hass , f " {{ {{ device_attr( ' { device_entry . id } ' , ' model ' ) }} }} " )
assert_result_info ( info , " test " )
assert info . rate_limit is None
# Test valid device attribute match (device_attr)
info = render_to_info (
hass , f " {{ {{ device_attr( ' { entity_entry . entity_id } ' , ' model ' ) }} }} "
)
assert_result_info ( info , " test " )
assert info . rate_limit is None
# Test valid device attribute mismatch (is_device_attr)
info = render_to_info (
hass , f " {{ {{ is_device_attr( ' { device_entry . id } ' , ' model ' , ' fail ' ) }} }} "
)
assert_result_info ( info , False )
assert info . rate_limit is None
# Test valid device attribute match (is_device_attr)
info = render_to_info (
hass , f " {{ {{ is_device_attr( ' { device_entry . id } ' , ' model ' , ' test ' ) }} }} "
)
assert_result_info ( info , True )
assert info . rate_limit is None
2022-11-24 07:31:17 +00:00
# Test filter syntax (device_attr)
info = render_to_info (
hass , f " {{ {{ ' { entity_entry . entity_id } ' | device_attr( ' model ' ) }} }} "
)
assert_result_info ( info , " test " )
assert info . rate_limit is None
# Test test syntax (is_device_attr)
info = render_to_info (
hass ,
2023-01-26 00:23:53 +00:00
(
f " {{ {{ [ ' { device_entry . id } ' ] | select( ' is_device_attr ' , ' model ' , ' test ' ) "
" | list }} "
) ,
2022-11-24 07:31:17 +00:00
)
assert_result_info ( info , [ device_entry . id ] )
assert info . rate_limit is None
2021-07-27 22:55:55 +00:00
2023-03-09 21:32:30 +00:00
async def test_areas ( hass : HomeAssistant , area_registry : ar . AreaRegistry ) - > None :
""" Test areas function. """
# Test no areas
info = render_to_info ( hass , " {{ areas() }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
# Test one area
area1 = area_registry . async_get_or_create ( " area1 " )
info = render_to_info ( hass , " {{ areas() }} " )
assert_result_info ( info , [ area1 . id ] )
assert info . rate_limit is None
# Test multiple areas
area2 = area_registry . async_get_or_create ( " area2 " )
info = render_to_info ( hass , " {{ areas() }} " )
assert_result_info ( info , [ area1 . id , area2 . id ] )
assert info . rate_limit is None
2023-02-09 01:15:29 +00:00
async def test_area_id (
hass : HomeAssistant ,
area_registry : ar . AreaRegistry ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2021-08-25 19:16:51 +00:00
""" Test area_id function. """
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-08-25 19:16:51 +00:00
# Test non existing entity id
info = render_to_info ( hass , " {{ area_id( ' sensor.fake ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test non existing device id (hex value)
info = render_to_info ( hass , " {{ area_id( ' 123abc ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test non existing area name
info = render_to_info ( hass , " {{ area_id( ' fake area name ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test wrong value type
info = render_to_info ( hass , " {{ area_id(56) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
area_entry_entity_id = area_registry . async_get_or_create ( " sensor.fake " )
# Test device with single entity, which has no area
device_entry = device_registry . async_get_or_create (
config_entry_id = config_entry . entry_id ,
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
)
entity_entry = entity_registry . async_get_or_create (
" light " ,
" hue " ,
" 5678 " ,
config_entry = config_entry ,
device_id = device_entry . id ,
)
info = render_to_info ( hass , f " {{ {{ area_id( ' { device_entry . id } ' ) }} }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_id( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test device ID, entity ID and area name as input with area name that looks like
# a device ID. Try a filter too
area_entry_hex = area_registry . async_get_or_create ( " 123abc " )
device_entry = device_registry . async_update_device (
device_entry . id , area_id = area_entry_hex . id
)
entity_entry = entity_registry . async_update_entity (
entity_entry . entity_id , area_id = area_entry_hex . id
)
info = render_to_info ( hass , f " {{ {{ ' { device_entry . id } ' | area_id }} }} " )
assert_result_info ( info , area_entry_hex . id )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_id( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , area_entry_hex . id )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_id( ' { area_entry_hex . name } ' ) }} }} " )
assert_result_info ( info , area_entry_hex . id )
assert info . rate_limit is None
# Test device ID, entity ID and area name as input with area name that looks like an
# entity ID
area_entry_entity_id = area_registry . async_get_or_create ( " sensor.fake " )
device_entry = device_registry . async_update_device (
device_entry . id , area_id = area_entry_entity_id . id
)
entity_entry = entity_registry . async_update_entity (
entity_entry . entity_id , area_id = area_entry_entity_id . id
)
info = render_to_info ( hass , f " {{ {{ area_id( ' { device_entry . id } ' ) }} }} " )
assert_result_info ( info , area_entry_entity_id . id )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_id( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , area_entry_entity_id . id )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_id( ' { area_entry_entity_id . name } ' ) }} }} " )
assert_result_info ( info , area_entry_entity_id . id )
assert info . rate_limit is None
2021-08-30 20:09:41 +00:00
# Make sure that when entity doesn't have an area but its device does, that's what
# gets returned
entity_entry = entity_registry . async_update_entity (
entity_entry . entity_id , area_id = area_entry_entity_id . id
)
info = render_to_info ( hass , f " {{ {{ area_id( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , area_entry_entity_id . id )
assert info . rate_limit is None
2021-08-25 19:16:51 +00:00
2023-02-09 01:15:29 +00:00
async def test_area_name (
hass : HomeAssistant ,
area_registry : ar . AreaRegistry ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2021-08-25 19:16:51 +00:00
""" Test area_name function. """
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-08-25 19:16:51 +00:00
# Test non existing entity id
info = render_to_info ( hass , " {{ area_name( ' sensor.fake ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test non existing device id (hex value)
info = render_to_info ( hass , " {{ area_name( ' 123abc ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test non existing area id
info = render_to_info ( hass , " {{ area_name( ' 1234567890 ' ) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test wrong value type
info = render_to_info ( hass , " {{ area_name(56) }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test device with single entity, which has no area
device_entry = device_registry . async_get_or_create (
config_entry_id = config_entry . entry_id ,
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
)
entity_entry = entity_registry . async_get_or_create (
" light " ,
" hue " ,
" 5678 " ,
config_entry = config_entry ,
device_id = device_entry . id ,
)
info = render_to_info ( hass , f " {{ {{ area_name( ' { device_entry . id } ' ) }} }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_name( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , None )
assert info . rate_limit is None
# Test device ID, entity ID and area id as input. Try a filter too
area_entry = area_registry . async_get_or_create ( " 123abc " )
device_entry = device_registry . async_update_device (
device_entry . id , area_id = area_entry . id
)
entity_entry = entity_registry . async_update_entity (
entity_entry . entity_id , area_id = area_entry . id
)
info = render_to_info ( hass , f " {{ {{ ' { device_entry . id } ' | area_name }} }} " )
assert_result_info ( info , area_entry . name )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_name( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , area_entry . name )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ area_name( ' { area_entry . id } ' ) }} }} " )
assert_result_info ( info , area_entry . name )
assert info . rate_limit is None
2021-08-30 20:09:41 +00:00
# Make sure that when entity doesn't have an area but its device does, that's what
# gets returned
entity_entry = entity_registry . async_update_entity (
entity_entry . entity_id , area_id = None
)
info = render_to_info ( hass , f " {{ {{ area_name( ' { entity_entry . entity_id } ' ) }} }} " )
assert_result_info ( info , area_entry . name )
assert info . rate_limit is None
2021-08-25 19:16:51 +00:00
2023-02-09 01:15:29 +00:00
async def test_area_entities (
hass : HomeAssistant ,
area_registry : ar . AreaRegistry ,
device_registry : dr . DeviceRegistry ,
entity_registry : er . EntityRegistry ,
) - > None :
2021-10-22 17:59:01 +00:00
""" Test area_entities function. """
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-10-22 17:59:01 +00:00
# Test non existing device id
info = render_to_info ( hass , " {{ area_entities( ' deadbeef ' ) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
# Test wrong value type
info = render_to_info ( hass , " {{ area_entities(56) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
area_entry = area_registry . async_get_or_create ( " sensor.fake " )
2022-09-02 11:31:05 +00:00
entity_entry = entity_registry . async_get_or_create (
2021-10-22 17:59:01 +00:00
" light " ,
" hue " ,
" 5678 " ,
config_entry = config_entry ,
)
2022-09-02 11:31:05 +00:00
entity_registry . async_update_entity ( entity_entry . entity_id , area_id = area_entry . id )
2021-10-22 17:59:01 +00:00
info = render_to_info ( hass , f " {{ {{ area_entities( ' { area_entry . id } ' ) }} }} " )
assert_result_info ( info , [ " light.hue_5678 " ] )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ ' { area_entry . name } ' | area_entities }} }} " )
assert_result_info ( info , [ " light.hue_5678 " ] )
assert info . rate_limit is None
# Test for entities that inherit area from device
device_entry = device_registry . async_get_or_create (
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
config_entry_id = config_entry . entry_id ,
suggested_area = " sensor.fake " ,
)
entity_registry . async_get_or_create (
" light " ,
" hue_light " ,
" 5678 " ,
config_entry = config_entry ,
device_id = device_entry . id ,
)
info = render_to_info ( hass , f " {{ {{ ' { area_entry . name } ' | area_entities }} }} " )
assert_result_info ( info , [ " light.hue_5678 " , " light.hue_light_5678 " ] )
assert info . rate_limit is None
2023-02-09 01:15:29 +00:00
async def test_area_devices (
hass : HomeAssistant ,
area_registry : ar . AreaRegistry ,
device_registry : dr . DeviceRegistry ,
) - > None :
2021-10-22 17:59:01 +00:00
""" Test area_devices function. """
config_entry = MockConfigEntry ( domain = " light " )
2023-08-10 17:28:16 +00:00
config_entry . add_to_hass ( hass )
2021-10-22 17:59:01 +00:00
# Test non existing device id
info = render_to_info ( hass , " {{ area_devices( ' deadbeef ' ) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
# Test wrong value type
info = render_to_info ( hass , " {{ area_devices(56) }} " )
assert_result_info ( info , [ ] )
assert info . rate_limit is None
area_entry = area_registry . async_get_or_create ( " sensor.fake " )
device_entry = device_registry . async_get_or_create (
config_entry_id = config_entry . entry_id ,
connections = { ( dr . CONNECTION_NETWORK_MAC , " 12:34:56:AB:CD:EF " ) } ,
suggested_area = area_entry . name ,
)
info = render_to_info ( hass , f " {{ {{ area_devices( ' { area_entry . id } ' ) }} }} " )
assert_result_info ( info , [ device_entry . id ] )
assert info . rate_limit is None
info = render_to_info ( hass , f " {{ {{ ' { area_entry . name } ' | area_devices }} }} " )
assert_result_info ( info , [ device_entry . id ] )
assert info . rate_limit is None
2022-11-23 19:28:52 +00:00
def test_closest_function_to_coord ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function to coord. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_home " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_zone " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.2 ,
" longitude " : hass . config . longitude + 0.2 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" zone.far_away " ,
" zoning " ,
{
" latitude " : hass . config . latitude + 0.3 ,
" longitude " : hass . config . longitude + 0.3 ,
} ,
)
2019-04-30 16:20:38 +00:00
tpl = template . Template (
2023-04-21 06:15:41 +00:00
f ' {{ {{ closest( " { hass . config . latitude + 0.3 } " , { hass . config . longitude + 0.3 } , states.test_domain).entity_id }} }} ' ,
2019-07-31 19:25:30 +00:00
hass ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " test_domain.closest_zone "
2019-04-30 16:20:38 +00:00
2019-06-22 07:32:32 +00:00
tpl = template . Template (
2023-04-21 06:15:41 +00:00
f ' {{ {{ (states.test_domain | closest( " { hass . config . latitude + 0.3 } " , { hass . config . longitude + 0.3 } )).entity_id }} }} ' ,
2019-07-31 19:25:30 +00:00
hass ,
)
2019-06-22 07:32:32 +00:00
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " test_domain.closest_zone "
2019-06-22 07:32:32 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_async_render_to_info_with_branching ( hass : HomeAssistant ) - > None :
2020-08-16 00:53:03 +00:00
""" Test async_render_to_info function by domain. """
hass . states . async_set ( " light.a " , " off " )
hass . states . async_set ( " light.b " , " on " )
hass . states . async_set ( " light.c " , " off " )
info = render_to_info (
hass ,
"""
{ % if states . light . a == " on " % }
{ { states . light . b . state } }
{ % else % }
{ { states . light . c . state } }
{ % endif % }
""" ,
)
assert_result_info ( info , " off " , { " light.a " , " light.c " } )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2020-08-16 00:53:03 +00:00
info = render_to_info (
hass ,
"""
{ % if states . light . a . state == " off " % }
{ % set domain = " light " % }
{ { states [ domain ] . b . state } }
{ % endif % }
""" ,
)
assert_result_info ( info , " on " , { " light.a " , " light.b " } )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2020-08-16 00:53:03 +00:00
2022-11-23 19:28:52 +00:00
def test_async_render_to_info_with_complex_branching ( hass : HomeAssistant ) - > None :
2020-08-16 00:53:03 +00:00
""" Test async_render_to_info function by domain. """
hass . states . async_set ( " light.a " , " off " )
hass . states . async_set ( " light.b " , " on " )
hass . states . async_set ( " light.c " , " off " )
hass . states . async_set ( " vacuum.a " , " off " )
hass . states . async_set ( " device_tracker.a " , " off " )
hass . states . async_set ( " device_tracker.b " , " off " )
hass . states . async_set ( " lock.a " , " off " )
hass . states . async_set ( " sensor.a " , " off " )
hass . states . async_set ( " binary_sensor.a " , " off " )
info = render_to_info (
hass ,
"""
{ % set domain = " vacuum " % }
{ % if states . light . a == " on " % }
{ { states . light . b . state } }
{ % elif states . light . a == " on " % }
{ { states . device_tracker } }
{ % elif states . light . a == " on " % }
{ { states [ domain ] | list } }
{ % elif states ( ' light.b ' ) == " on " % }
2023-03-31 21:27:55 +00:00
{ { states [ otherdomain ] | sort ( attribute = ' entity_id ' ) | map ( attribute = ' entity_id ' ) | list } }
2020-08-16 00:53:03 +00:00
{ % elif states . light . a == " on " % }
{ { states [ " nonexist " ] | list } }
{ % else % }
else
{ % endif % }
""" ,
{ " otherdomain " : " sensor " } ,
)
2020-10-06 22:05:52 +00:00
assert_result_info ( info , [ " sensor.a " ] , { " light.a " , " light.b " } , { " sensor " } )
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . DOMAIN_STATES_RATE_LIMIT
2020-08-16 00:53:03 +00:00
2022-11-23 19:28:52 +00:00
async def test_async_render_to_info_with_wildcard_matching_entity_id (
hass : HomeAssistant ,
) - > None :
2020-08-16 00:53:03 +00:00
""" Test tracking template with a wildcard. """
template_complex_str = r """
2020-10-06 05:25:05 +00:00
{ % for state in states . cover % }
2023-08-04 09:25:08 +00:00
{ % if state . entity_id | regex_match ( ' .* \\ .office_ ' ) % }
2020-08-16 00:53:03 +00:00
{ { state . entity_id } } = { { state . state } }
{ % endif % }
{ % endfor % }
"""
hass . states . async_set ( " cover.office_drapes " , " closed " )
hass . states . async_set ( " cover.office_window " , " closed " )
hass . states . async_set ( " cover.office_skylight " , " open " )
info = render_to_info ( hass , template_complex_str )
2020-10-06 05:25:05 +00:00
assert info . domains == { " cover " }
assert info . entities == set ( )
assert info . all_states is False
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . DOMAIN_STATES_RATE_LIMIT
2020-08-16 00:53:03 +00:00
2022-11-23 19:28:52 +00:00
async def test_async_render_to_info_with_wildcard_matching_state (
hass : HomeAssistant ,
) - > None :
2020-08-16 00:53:03 +00:00
""" Test tracking template with a wildcard. """
template_complex_str = """
{ % for state in states % }
{ % if state . state | regex_match ( ' ope.* ' ) % }
{ { state . entity_id } } = { { state . state } }
{ % endif % }
{ % endfor % }
"""
hass . states . async_set ( " cover.office_drapes " , " closed " )
hass . states . async_set ( " cover.office_window " , " closed " )
hass . states . async_set ( " cover.office_skylight " , " open " )
hass . states . async_set ( " cover.x_skylight " , " open " )
hass . states . async_set ( " binary_sensor.door " , " open " )
2020-10-19 09:02:43 +00:00
await hass . async_block_till_done ( )
2020-08-16 00:53:03 +00:00
info = render_to_info ( hass , template_complex_str )
assert not info . domains
2020-10-06 05:25:05 +00:00
assert info . entities == set ( )
2020-08-16 00:53:03 +00:00
assert info . all_states is True
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . ALL_STATES_RATE_LIMIT
2020-08-16 00:53:03 +00:00
hass . states . async_set ( " binary_sensor.door " , " closed " )
info = render_to_info ( hass , template_complex_str )
assert not info . domains
2020-10-06 05:25:05 +00:00
assert info . entities == set ( )
2020-08-16 00:53:03 +00:00
assert info . all_states is True
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . ALL_STATES_RATE_LIMIT
2020-08-16 00:53:03 +00:00
template_cover_str = """
{ % for state in states . cover % }
{ % if state . state | regex_match ( ' ope.* ' ) % }
{ { state . entity_id } } = { { state . state } }
{ % endif % }
{ % endfor % }
"""
hass . states . async_set ( " cover.x_skylight " , " closed " )
info = render_to_info ( hass , template_cover_str )
assert info . domains == { " cover " }
2020-10-06 05:25:05 +00:00
assert info . entities == set ( )
2020-08-16 00:53:03 +00:00
assert info . all_states is False
2020-10-19 08:18:25 +00:00
assert info . rate_limit == template . DOMAIN_STATES_RATE_LIMIT
2020-08-16 00:53:03 +00:00
2022-11-23 19:28:52 +00:00
def test_nested_async_render_to_info_case ( hass : HomeAssistant ) - > None :
2020-08-16 00:53:03 +00:00
""" Test a deeply nested state with async_render_to_info. """
hass . states . async_set ( " input_select.picker " , " vacuum.a " )
hass . states . async_set ( " vacuum.a " , " off " )
info = render_to_info (
hass , " {{ states[states[ ' input_select.picker ' ].state].state }} " , { }
)
assert_result_info ( info , " off " , { " input_select.picker " , " vacuum.a " } )
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2020-08-16 00:53:03 +00:00
2022-11-23 19:28:52 +00:00
def test_result_as_boolean ( hass : HomeAssistant ) - > None :
2020-08-16 00:53:03 +00:00
""" Test converting a template result to a boolean. """
2020-09-04 14:28:56 +00:00
assert template . result_as_boolean ( True ) is True
assert template . result_as_boolean ( " 1 " ) is True
assert template . result_as_boolean ( " true " ) is True
assert template . result_as_boolean ( " TrUE " ) is True
assert template . result_as_boolean ( " YeS " ) is True
assert template . result_as_boolean ( " On " ) is True
assert template . result_as_boolean ( " Enable " ) is True
assert template . result_as_boolean ( 1 ) is True
assert template . result_as_boolean ( - 1 ) is True
assert template . result_as_boolean ( 500 ) is True
assert template . result_as_boolean ( 0.5 ) is True
assert template . result_as_boolean ( 0.389 ) is True
assert template . result_as_boolean ( 35 ) is True
assert template . result_as_boolean ( False ) is False
assert template . result_as_boolean ( " 0 " ) is False
assert template . result_as_boolean ( " false " ) is False
assert template . result_as_boolean ( " FaLsE " ) is False
assert template . result_as_boolean ( " no " ) is False
assert template . result_as_boolean ( " off " ) is False
assert template . result_as_boolean ( " disable " ) is False
assert template . result_as_boolean ( 0 ) is False
assert template . result_as_boolean ( 0.0 ) is False
assert template . result_as_boolean ( " 0.00 " ) is False
assert template . result_as_boolean ( None ) is False
2020-08-16 00:53:03 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_to_entity_id ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function to entity id. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_home " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_zone " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.2 ,
" longitude " : hass . config . longitude + 0.2 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" zone.far_away " ,
" zoning " ,
{
" latitude " : hass . config . latitude + 0.3 ,
" longitude " : hass . config . longitude + 0.3 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-05-01 02:54:25 +00:00
info = render_to_info (
hass ,
2019-07-31 19:25:30 +00:00
" {{ closest(zone, states.test_domain).entity_id }} " ,
{ " zone " : " zone.far_away " } ,
)
2019-05-01 02:54:25 +00:00
assert_result_info (
2019-07-31 19:25:30 +00:00
info ,
" test_domain.closest_zone " ,
[ " test_domain.closest_home " , " test_domain.closest_zone " , " zone.far_away " ] ,
[ " test_domain " ] ,
)
2019-04-30 16:20:38 +00:00
2019-06-22 07:32:32 +00:00
info = render_to_info (
hass ,
2023-01-26 00:23:53 +00:00
(
" {{ ([states.test_domain, ' test_domain.closest_zone ' ] "
" | closest(zone)).entity_id }} "
) ,
2019-07-31 19:25:30 +00:00
{ " zone " : " zone.far_away " } ,
)
2019-06-22 07:32:32 +00:00
assert_result_info (
2019-07-31 19:25:30 +00:00
info ,
" test_domain.closest_zone " ,
[ " test_domain.closest_home " , " test_domain.closest_zone " , " zone.far_away " ] ,
[ " test_domain " ] ,
)
2019-06-22 07:32:32 +00:00
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_to_state ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function to state. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_home " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_zone " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.2 ,
" longitude " : hass . config . longitude + 0.2 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" zone.far_away " ,
" zoning " ,
{
" latitude " : hass . config . latitude + 0.3 ,
" longitude " : hass . config . longitude + 0.3 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
2020-01-02 19:17:10 +00:00
" {{ closest(states.zone.far_away, states.test_domain).entity_id }} " , hass
2019-07-31 19:25:30 +00:00
) . async_render ( )
== " test_domain.closest_zone "
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_invalid_state ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function invalid state. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_home " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
for state in ( " states.zone.non_existing " , ' " zone.non_existing " ' ) :
assert (
template . Template ( " {{ closest( %s , states) }} " % state , hass ) . async_render ( )
2020-10-06 22:05:52 +00:00
is None
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_state_with_invalid_location ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function state with invalid location. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_home " ,
" happy " ,
{ " latitude " : " invalid latitude " , " longitude " : hass . config . longitude + 0.1 } ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
2020-01-02 19:17:10 +00:00
" {{ closest(states.test_domain.closest_home, states) }} " , hass
2019-07-31 19:25:30 +00:00
) . async_render ( )
2020-10-06 22:05:52 +00:00
is None
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_invalid_coordinates ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function invalid coordinates. """
2019-07-31 19:25:30 +00:00
hass . states . async_set (
" test_domain.closest_home " ,
" happy " ,
{
" latitude " : hass . config . latitude + 0.1 ,
" longitude " : hass . config . longitude + 0.1 ,
} ,
)
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
assert (
template . Template (
' {{ closest( " invalid " , " coord " , states) }} ' , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
is None
2019-07-31 19:25:30 +00:00
)
assert (
template . Template (
' {{ states | closest( " invalid " , " coord " ) }} ' , hass
) . async_render ( )
2020-10-06 22:05:52 +00:00
is None
2019-07-31 19:25:30 +00:00
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_closest_function_no_location_states ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test closest function without location states. """
2019-07-31 19:25:30 +00:00
assert (
template . Template ( " {{ closest(states).entity_id }} " , hass ) . async_render ( ) == " "
)
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_generate_filter_iterators ( hass : HomeAssistant ) - > None :
2019-05-01 02:54:25 +00:00
""" Test extract entities function with none entities stuff. """
2019-07-31 19:25:30 +00:00
info = render_to_info (
hass ,
"""
2019-05-01 02:54:25 +00:00
{ % for state in states % }
{ { state . entity_id } }
{ % endfor % }
2019-07-31 19:25:30 +00:00
""" ,
)
assert_result_info ( info , " " , all_states = True )
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
info = render_to_info (
hass ,
"""
2019-05-01 02:54:25 +00:00
{ % for state in states . sensor % }
{ { state . entity_id } }
{ % endfor % }
2019-07-31 19:25:30 +00:00
""" ,
)
assert_result_info ( info , " " , domains = [ " sensor " ] )
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.test_sensor " , " off " , { " attr " : " value " } )
2019-05-01 02:54:25 +00:00
# Don't need the entity because the state is not accessed
2019-07-31 19:25:30 +00:00
info = render_to_info (
hass ,
"""
2019-05-01 02:54:25 +00:00
{ % for state in states . sensor % }
{ { state . entity_id } }
{ % endfor % }
2019-07-31 19:25:30 +00:00
""" ,
)
assert_result_info ( info , " sensor.test_sensor " , domains = [ " sensor " ] )
2019-05-01 02:54:25 +00:00
# But we do here because the state gets accessed
2019-07-31 19:25:30 +00:00
info = render_to_info (
hass ,
"""
2019-05-01 02:54:25 +00:00
{ % for state in states . sensor % }
{ { state . entity_id } } = { { state . state } } ,
{ % endfor % }
2019-07-31 19:25:30 +00:00
""" ,
)
2020-10-06 05:25:05 +00:00
assert_result_info ( info , " sensor.test_sensor=off, " , [ ] , [ " sensor " ] )
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
info = render_to_info (
hass ,
"""
2019-05-01 02:54:25 +00:00
{ % for state in states . sensor % }
{ { state . entity_id } } = { { state . attributes . attr } } ,
{ % endfor % }
2019-07-31 19:25:30 +00:00
""" ,
)
2020-10-06 05:25:05 +00:00
assert_result_info ( info , " sensor.test_sensor=value, " , [ ] , [ " sensor " ] )
2019-05-01 02:54:25 +00:00
2022-11-23 19:28:52 +00:00
def test_generate_select ( hass : HomeAssistant ) - > None :
2019-05-01 02:54:25 +00:00
""" Test extract entities function with none entities stuff. """
template_str = """
{ { states . sensor | selectattr ( " state " , " equalto " , " off " )
| join ( " , " , attribute = " entity_id " ) } }
"""
tmp = template . Template ( template_str , hass )
info = tmp . async_render_to_info ( )
2020-09-26 21:29:49 +00:00
assert_result_info ( info , " " , [ ] , [ ] )
assert info . domains_lifecycle == { " sensor " }
2019-05-01 02:54:25 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.test_sensor " , " off " , { " attr " : " value " } )
hass . states . async_set ( " sensor.test_sensor_on " , " on " )
2019-05-01 02:54:25 +00:00
info = tmp . async_render_to_info ( )
assert_result_info (
2019-07-31 19:25:30 +00:00
info ,
" sensor.test_sensor " ,
2020-10-06 05:25:05 +00:00
[ ] ,
2019-07-31 19:25:30 +00:00
[ " sensor " ] ,
)
2020-09-26 21:29:49 +00:00
assert info . domains_lifecycle == { " sensor " }
2019-04-30 16:20:38 +00:00
2016-09-28 04:29:55 +00:00
2022-11-23 19:28:52 +00:00
async def test_async_render_to_info_in_conditional ( hass : HomeAssistant ) - > None :
2020-08-16 00:53:03 +00:00
""" Test extract entities function with none entities stuff. """
template_str = """
{ { states ( " sensor.xyz " ) == " dog " } }
"""
tmp = template . Template ( template_str , hass )
info = tmp . async_render_to_info ( )
2020-10-06 22:05:52 +00:00
assert_result_info ( info , False , [ " sensor.xyz " ] , [ ] )
2020-08-16 00:53:03 +00:00
hass . states . async_set ( " sensor.xyz " , " dog " )
hass . states . async_set ( " sensor.cow " , " True " )
await hass . async_block_till_done ( )
template_str = """
{ % if states ( " sensor.xyz " ) == " dog " % }
{ { states ( " sensor.cow " ) } }
{ % else % }
{ { states ( " sensor.pig " ) } }
{ % endif % }
"""
tmp = template . Template ( template_str , hass )
info = tmp . async_render_to_info ( )
2020-10-06 22:05:52 +00:00
assert_result_info ( info , True , [ " sensor.xyz " , " sensor.cow " ] , [ ] )
2020-08-16 00:53:03 +00:00
hass . states . async_set ( " sensor.xyz " , " sheep " )
hass . states . async_set ( " sensor.pig " , " oink " )
await hass . async_block_till_done ( )
tmp = template . Template ( template_str , hass )
info = tmp . async_render_to_info ( )
assert_result_info ( info , " oink " , [ " sensor.xyz " , " sensor.pig " ] , [ ] )
2022-11-23 19:28:52 +00:00
def test_jinja_namespace ( hass : HomeAssistant ) - > None :
2019-04-30 16:20:38 +00:00
""" Test Jinja ' s namespace command can be used. """
test_template = template . Template (
(
" { % s et ns = namespace(a_key= ' ' ) % } "
" { % s et ns.a_key = states.sensor.dummy.state % } "
" {{ ns.a_key }} "
) ,
2019-07-31 19:25:30 +00:00
hass ,
2019-04-30 16:20:38 +00:00
)
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.dummy " , " a value " )
assert test_template . async_render ( ) == " a value "
2019-04-30 16:20:38 +00:00
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.dummy " , " another value " )
assert test_template . async_render ( ) == " another value "
2019-04-30 16:20:38 +00:00
2022-11-23 19:28:52 +00:00
def test_state_with_unit ( hass : HomeAssistant ) - > None :
2017-08-18 06:19:35 +00:00
""" Test the state_with_unit property helper. """
2020-09-21 21:03:39 +00:00
hass . states . async_set ( " sensor.test " , " 23 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.test2 " , " wow " )
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ states.sensor.test.state_with_unit }} " , hass )
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " 23 beers "
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ states.sensor.test2.state_with_unit }} " , hass )
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " wow "
2017-08-18 06:19:35 +00:00
tpl = template . Template (
2019-07-31 19:25:30 +00:00
" { % f or state in states % } {{ state.state_with_unit }} { % e ndfor % } " , hass
)
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " 23 beers wow "
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ states.sensor.non_existing.state_with_unit }} " , hass )
2017-08-18 06:19:35 +00:00
2019-07-31 19:25:30 +00:00
assert tpl . async_render ( ) == " "
2017-08-27 16:33:25 +00:00
2023-02-09 11:54:59 +00:00
def test_state_with_unit_and_rounding ( hass : HomeAssistant ) - > None :
""" Test formatting the state rounded and with unit. """
entity_registry = er . async_get ( hass )
entry = entity_registry . async_get_or_create (
" sensor " , " test " , " very_unique " , suggested_object_id = " test "
)
entity_registry . async_update_entity_options (
entry . entity_id ,
" sensor " ,
{
" suggested_display_precision " : 2 ,
} ,
)
assert entry . entity_id == " sensor.test "
hass . states . async_set ( " sensor.test " , " 23 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
hass . states . async_set ( " sensor.test2 " , " 23 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
2023-07-03 01:53:50 +00:00
hass . states . async_set ( " sensor.test3 " , " -0.0 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
hass . states . async_set ( " sensor.test4 " , " -0 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
2023-02-09 11:54:59 +00:00
# state_with_unit property
tpl = template . Template ( " {{ states.sensor.test.state_with_unit }} " , hass )
tpl2 = template . Template ( " {{ states.sensor.test2.state_with_unit }} " , hass )
# AllStates.__call__ defaults
tpl3 = template . Template ( " {{ states( ' sensor.test ' ) }} " , hass )
tpl4 = template . Template ( " {{ states( ' sensor.test2 ' ) }} " , hass )
# AllStates.__call__ and with_unit=True
tpl5 = template . Template ( " {{ states( ' sensor.test ' , with_unit=True) }} " , hass )
tpl6 = template . Template ( " {{ states( ' sensor.test2 ' , with_unit=True) }} " , hass )
# AllStates.__call__ and rounded=True
tpl7 = template . Template ( " {{ states( ' sensor.test ' , rounded=True) }} " , hass )
tpl8 = template . Template ( " {{ states( ' sensor.test2 ' , rounded=True) }} " , hass )
2023-07-03 01:53:50 +00:00
tpl9 = template . Template ( " {{ states( ' sensor.test3 ' , rounded=True) }} " , hass )
tpl10 = template . Template ( " {{ states( ' sensor.test4 ' , rounded=True) }} " , hass )
2023-02-09 11:54:59 +00:00
assert tpl . async_render ( ) == " 23.00 beers "
assert tpl2 . async_render ( ) == " 23 beers "
assert tpl3 . async_render ( ) == 23
assert tpl4 . async_render ( ) == 23
assert tpl5 . async_render ( ) == " 23.00 beers "
assert tpl6 . async_render ( ) == " 23 beers "
assert tpl7 . async_render ( ) == 23.0
assert tpl8 . async_render ( ) == 23
2023-07-03 01:53:50 +00:00
assert tpl9 . async_render ( ) == 0.0
assert tpl10 . async_render ( ) == 0
2023-02-09 11:54:59 +00:00
hass . states . async_set ( " sensor.test " , " 23.015 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
hass . states . async_set ( " sensor.test2 " , " 23.015 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
assert tpl . async_render ( ) == " 23.02 beers "
assert tpl2 . async_render ( ) == " 23.015 beers "
assert tpl3 . async_render ( ) == 23.015
assert tpl4 . async_render ( ) == 23.015
assert tpl5 . async_render ( ) == " 23.02 beers "
assert tpl6 . async_render ( ) == " 23.015 beers "
assert tpl7 . async_render ( ) == 23.02
assert tpl8 . async_render ( ) == 23.015
@pytest.mark.parametrize (
( " rounded " , " with_unit " , " output1_1 " , " output1_2 " , " output2_1 " , " output2_2 " ) ,
[
( False , False , 23 , 23.015 , 23 , 23.015 ) ,
( False , True , " 23 beers " , " 23.015 beers " , " 23 beers " , " 23.015 beers " ) ,
( True , False , 23.0 , 23.02 , 23 , 23.015 ) ,
( True , True , " 23.00 beers " , " 23.02 beers " , " 23 beers " , " 23.015 beers " ) ,
] ,
)
def test_state_with_unit_and_rounding_options (
hass : HomeAssistant ,
rounded : str ,
with_unit : str ,
output1_1 ,
output1_2 ,
output2_1 ,
output2_2 ,
) - > None :
""" Test formatting the state rounded and with unit. """
entity_registry = er . async_get ( hass )
entry = entity_registry . async_get_or_create (
" sensor " , " test " , " very_unique " , suggested_object_id = " test "
)
entity_registry . async_update_entity_options (
entry . entity_id ,
" sensor " ,
{
" suggested_display_precision " : 2 ,
} ,
)
assert entry . entity_id == " sensor.test "
hass . states . async_set ( " sensor.test " , " 23 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
hass . states . async_set ( " sensor.test2 " , " 23 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
tpl = template . Template (
f " {{ {{ states( ' sensor.test ' , rounded= { rounded } , with_unit= { with_unit } ) }} }} " ,
hass ,
)
tpl2 = template . Template (
f " {{ {{ states( ' sensor.test2 ' , rounded= { rounded } , with_unit= { with_unit } ) }} }} " ,
hass ,
)
assert tpl . async_render ( ) == output1_1
assert tpl2 . async_render ( ) == output2_1
hass . states . async_set ( " sensor.test " , " 23.015 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
hass . states . async_set ( " sensor.test2 " , " 23.015 " , { ATTR_UNIT_OF_MEASUREMENT : " beers " } )
assert tpl . async_render ( ) == output1_2
assert tpl2 . async_render ( ) == output2_2
2022-11-23 19:28:52 +00:00
def test_length_of_states ( hass : HomeAssistant ) - > None :
2017-08-27 16:33:25 +00:00
""" Test fetching the length of states. """
2019-07-31 19:25:30 +00:00
hass . states . async_set ( " sensor.test " , " 23 " )
hass . states . async_set ( " sensor.test2 " , " wow " )
hass . states . async_set ( " climate.test2 " , " cooling " )
2017-08-27 16:33:25 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ states | length }} " , hass )
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 3
2017-08-27 16:33:25 +00:00
2019-07-31 19:25:30 +00:00
tpl = template . Template ( " {{ states.sensor | length }} " , hass )
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 2
2019-12-03 22:15:45 +00:00
2022-11-23 19:28:52 +00:00
def test_render_complex_handling_non_template_values ( hass : HomeAssistant ) - > None :
2019-12-03 22:15:45 +00:00
""" Test that we can render non-template fields. """
assert template . render_complex (
{ True : 1 , False : template . Template ( " {{ hello }} " , hass ) } , { " hello " : 2 }
2020-10-06 22:05:52 +00:00
) == { True : 1 , False : 2 }
2020-07-13 14:48:29 +00:00
2022-11-23 19:28:52 +00:00
def test_urlencode ( hass : HomeAssistant ) - > None :
2020-07-13 14:48:29 +00:00
""" Test the urlencode method. """
tpl = template . Template (
2023-01-26 00:23:53 +00:00
" { % s et dict = { ' foo ' : ' x&y ' , ' bar ' : 42} % } {{ dict | urlencode }} " ,
2020-08-27 11:56:20 +00:00
hass ,
2020-07-13 14:48:29 +00:00
)
assert tpl . async_render ( ) == " foo=x % 26y&bar=42 "
tpl = template . Template (
2023-01-26 00:23:53 +00:00
" { % s et string = ' the quick brown fox = true ' % } {{ string | urlencode }} " ,
2020-07-13 14:48:29 +00:00
hass ,
)
assert tpl . async_render ( ) == " the % 20quick % 20brown %20f ox %20% 3D % 20true "
2020-08-04 01:00:44 +00:00
2022-05-23 17:32:22 +00:00
def test_as_timedelta ( hass : HomeAssistant ) - > None :
""" Test the as_timedelta function/filter. """
tpl = template . Template ( " {{ as_timedelta( ' PT10M ' ) }} " , hass )
assert tpl . async_render ( ) == " 0:10:00 "
tpl = template . Template ( " {{ ' PT10M ' | as_timedelta }} " , hass )
assert tpl . async_render ( ) == " 0:10:00 "
tpl = template . Template ( " {{ ' T10M ' | as_timedelta }} " , hass )
assert tpl . async_render ( ) is None
2021-12-21 16:25:07 +00:00
def test_iif ( hass : HomeAssistant ) - > None :
""" Test the immediate if function/filter. """
tpl = template . Template ( " {{ (1 == 1) | iif }} " , hass )
assert tpl . async_render ( ) is True
tpl = template . Template ( " {{ (1 == 2) | iif }} " , hass )
assert tpl . async_render ( ) is False
tpl = template . Template ( " {{ (1 == 1) | iif( ' yes ' ) }} " , hass )
assert tpl . async_render ( ) == " yes "
tpl = template . Template ( " {{ (1 == 2) | iif( ' yes ' ) }} " , hass )
assert tpl . async_render ( ) is False
tpl = template . Template ( " {{ (1 == 2) | iif( ' yes ' , ' no ' ) }} " , hass )
assert tpl . async_render ( ) == " no "
tpl = template . Template ( " {{ not_exists | default(None) | iif( ' yes ' , ' no ' ) }} " , hass )
assert tpl . async_render ( ) == " no "
tpl = template . Template (
" {{ not_exists | default(None) | iif( ' yes ' , ' no ' , ' unknown ' ) }} " , hass
)
assert tpl . async_render ( ) == " unknown "
tpl = template . Template ( " {{ iif(1 == 1) }} " , hass )
assert tpl . async_render ( ) is True
tpl = template . Template ( " {{ iif(1 == 2, ' yes ' , ' no ' ) }} " , hass )
assert tpl . async_render ( ) == " no "
2022-11-23 19:28:52 +00:00
async def test_cache_garbage_collection ( ) - > None :
2020-08-04 01:00:44 +00:00
""" Test caching a template. """
template_string = (
" { % s et dict = { ' foo ' : ' x&y ' , ' bar ' : 42} % } {{ dict | urlencode }} "
)
2020-08-27 11:56:20 +00:00
tpl = template . Template (
( template_string ) ,
)
2020-08-04 01:00:44 +00:00
tpl . ensure_valid ( )
2023-01-22 16:26:24 +00:00
assert template . _NO_HASS_ENV . template_cache . get ( template_string )
2020-08-04 01:00:44 +00:00
2020-08-27 11:56:20 +00:00
tpl2 = template . Template (
( template_string ) ,
)
2020-08-04 01:00:44 +00:00
tpl2 . ensure_valid ( )
2023-01-22 16:26:24 +00:00
assert template . _NO_HASS_ENV . template_cache . get ( template_string )
2020-08-04 01:00:44 +00:00
del tpl
2023-01-22 16:26:24 +00:00
assert template . _NO_HASS_ENV . template_cache . get ( template_string )
2020-08-04 01:00:44 +00:00
del tpl2
2023-01-22 16:26:24 +00:00
assert not template . _NO_HASS_ENV . template_cache . get ( template_string )
2020-08-31 08:51:30 +00:00
2022-11-23 19:28:52 +00:00
def test_is_template_string ( ) - > None :
2020-08-31 08:51:30 +00:00
""" Test is template string. """
assert template . is_template_string ( " {{ x }} " ) is True
assert template . is_template_string ( " { % i f x == 2 % }1 { % e lse % }0 { %e nd if % } " ) is True
assert template . is_template_string ( " { # a comment #} Hey " ) is True
assert template . is_template_string ( " 1 " ) is False
assert template . is_template_string ( " Some Text " ) is False
2020-09-07 15:33:22 +00:00
2022-11-23 19:28:52 +00:00
async def test_protected_blocked ( hass : HomeAssistant ) - > None :
2020-09-07 15:33:22 +00:00
""" Test accessing __getattr__ produces a template error. """
tmp = template . Template ( ' {{ states.__getattr__( " any " ) }} ' , hass )
with pytest . raises ( TemplateError ) :
tmp . async_render ( )
tmp = template . Template ( ' {{ states.sensor.__getattr__( " any " ) }} ' , hass )
with pytest . raises ( TemplateError ) :
tmp . async_render ( )
tmp = template . Template ( ' {{ states.sensor.any.__getattr__( " any " ) }} ' , hass )
with pytest . raises ( TemplateError ) :
tmp . async_render ( )
2020-09-10 18:43:45 +00:00
2022-11-23 19:28:52 +00:00
async def test_demo_template ( hass : HomeAssistant ) - > None :
2020-09-10 18:43:45 +00:00
""" Test the demo template works as expected. """
2022-05-13 16:46:49 +00:00
hass . states . async_set (
" sun.sun " ,
" above " ,
{ " elevation " : 50 , " next_rising " : " 2022-05-12T03:00:08.503651+00:00 " } ,
)
2020-09-10 18:43:45 +00:00
for i in range ( 2 ) :
hass . states . async_set ( f " sensor.sensor { i } " , " on " )
demo_template_str = """
{ ## Imitate available variables: ##}
{ % set my_test_json = {
" temperature " : 25 ,
" unit " : " °C "
} % }
The temperature is { { my_test_json . temperature } } { { my_test_json . unit } } .
{ % if is_state ( " sun.sun " , " above_horizon " ) - % }
The sun rose { { relative_time ( states . sun . sun . last_changed ) } } ago .
{ % - else - % }
2022-05-13 16:46:49 +00:00
The sun will rise at { { as_timestamp ( state_attr ( " sun.sun " , " next_rising " ) ) | timestamp_local } } .
2020-09-10 18:43:45 +00:00
{ % - endif % }
For loop example getting 3 entity values :
{ % for states in states | slice ( 3 ) - % }
{ % set state = states | first % }
{ % - if loop . first % } The { % elif loop . last % } and the { % else % } , the { % endif - % }
{ { state . name | lower } } is { { state . state_with_unit } }
{ % - endfor % } .
"""
tmp = template . Template ( demo_template_str , hass )
result = tmp . async_render ( )
assert " The temperature is 25 " in result
assert " is on " in result
assert " sensor0 " in result
assert " sensor1 " in result
assert " sun " in result
2020-09-26 16:36:47 +00:00
2022-11-23 19:28:52 +00:00
async def test_slice_states ( hass : HomeAssistant ) - > None :
2020-09-26 16:36:47 +00:00
""" Test iterating states with a slice. """
hass . states . async_set ( " sensor.test " , " 23 " )
tpl = template . Template (
2023-01-26 00:23:53 +00:00
(
" { % f or states in states | slice(1) - % } { % s et state = states | first % } "
" {{ state.entity_id }} "
" { %- e ndfor % } "
) ,
2020-09-26 16:36:47 +00:00
hass ,
)
assert tpl . async_render ( ) == " sensor.test "
2020-09-26 21:29:49 +00:00
2022-11-23 19:28:52 +00:00
async def test_lifecycle ( hass : HomeAssistant ) - > None :
2020-09-26 21:29:49 +00:00
""" Test that we limit template render info for lifecycle events. """
hass . states . async_set ( " sun.sun " , " above " , { " elevation " : 50 , " next_rising " : " later " } )
for i in range ( 2 ) :
hass . states . async_set ( f " sensor.sensor { i } " , " on " )
2020-10-19 09:02:43 +00:00
hass . states . async_set ( " sensor.removed " , " off " )
await hass . async_block_till_done ( )
hass . states . async_set ( " sun.sun " , " below " , { " elevation " : 60 , " next_rising " : " later " } )
for i in range ( 2 ) :
hass . states . async_set ( f " sensor.sensor { i } " , " off " )
hass . states . async_set ( " sensor.new " , " off " )
hass . states . async_remove ( " sensor.removed " )
await hass . async_block_till_done ( )
2020-09-26 21:29:49 +00:00
tmp = template . Template ( " {{ states | count }} " , hass )
info = tmp . async_render_to_info ( )
assert info . all_states is False
assert info . all_states_lifecycle is True
2020-10-01 19:39:44 +00:00
assert info . rate_limit is None
2020-10-19 09:02:43 +00:00
assert info . has_time is False
2020-09-26 21:29:49 +00:00
assert info . entities == set ( )
assert info . domains == set ( )
assert info . domains_lifecycle == set ( )
assert info . filter ( " sun.sun " ) is False
assert info . filter ( " sensor.sensor1 " ) is False
assert info . filter_lifecycle ( " sensor.new " ) is True
assert info . filter_lifecycle ( " sensor.removed " ) is True
2020-09-28 12:43:22 +00:00
2022-11-23 19:28:52 +00:00
async def test_template_timeout ( hass : HomeAssistant ) - > None :
2020-09-28 12:43:22 +00:00
""" Test to see if a template will timeout. """
for i in range ( 2 ) :
hass . states . async_set ( f " sensor.sensor { i } " , " on " )
tmp = template . Template ( " {{ states | count }} " , hass )
assert await tmp . async_render_will_timeout ( 3 ) is False
tmp3 = template . Template ( " static " , hass )
assert await tmp3 . async_render_will_timeout ( 3 ) is False
tmp4 = template . Template ( " {{ var1 }} " , hass )
assert await tmp4 . async_render_will_timeout ( 3 , { " var1 " : " ok " } ) is False
slow_template_str = """
{ % for var in range ( 1000 ) - % }
{ % for var in range ( 1000 ) - % }
{ { var } }
{ % - endfor % }
{ % - endfor % }
"""
tmp5 = template . Template ( slow_template_str , hass )
assert await tmp5 . async_render_will_timeout ( 0.000001 ) is True
2020-09-28 15:35:12 +00:00
2022-11-23 19:28:52 +00:00
async def test_template_timeout_raise ( hass : HomeAssistant ) - > None :
2021-04-09 19:10:02 +00:00
""" Test we can raise from. """
tmp2 = template . Template ( " {{ error_invalid + 1 }} " , hass )
with pytest . raises ( TemplateError ) :
assert await tmp2 . async_render_will_timeout ( 3 ) is False
2022-11-23 19:28:52 +00:00
async def test_lights ( hass : HomeAssistant ) - > None :
2020-09-28 15:35:12 +00:00
""" Test we can sort lights. """
tmpl = """
2023-03-31 21:27:55 +00:00
{ % set lights_on = states . light | selectattr ( ' state ' , ' eq ' , ' on ' ) | sort ( attribute = ' entity_id ' ) | map ( attribute = ' name ' ) | list % }
2020-09-28 15:35:12 +00:00
{ % if lights_on | length == 0 % }
No lights on . Sleep well . .
{ % elif lights_on | length == 1 % }
The { { lights_on [ 0 ] } } light is on .
{ % elif lights_on | length == 2 % }
The { { lights_on [ 0 ] } } and { { lights_on [ 1 ] } } lights are on .
{ % else % }
The { { lights_on [ : - 1 ] | join ( ' , ' ) } } , and { { lights_on [ - 1 ] } } lights are on .
{ % endif % }
"""
states = [ ]
for i in range ( 10 ) :
states . append ( f " light.sensor { i } " )
hass . states . async_set ( f " light.sensor { i } " , " on " )
tmp = template . Template ( tmpl , hass )
info = tmp . async_render_to_info ( )
2020-10-06 05:25:05 +00:00
assert info . entities == set ( )
assert info . domains == { " light " }
2020-09-28 15:35:12 +00:00
assert " lights are on " in info . result ( )
for i in range ( 10 ) :
assert f " sensor { i } " in info . result ( )
2022-11-23 19:28:52 +00:00
async def test_template_errors ( hass : HomeAssistant ) - > None :
2020-10-12 14:38:24 +00:00
""" Test template rendering wraps exceptions with TemplateError. """
with pytest . raises ( TemplateError ) :
template . Template ( " {{ now() | rando }} " , hass ) . async_render ( )
2020-10-19 09:02:43 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ utcnow() | rando }} " , hass ) . async_render ( )
2020-10-12 14:38:24 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ now() | random }} " , hass ) . async_render ( )
2020-10-19 09:02:43 +00:00
with pytest . raises ( TemplateError ) :
template . Template ( " {{ utcnow() | random }} " , hass ) . async_render ( )
2020-10-12 14:38:24 +00:00
2022-11-23 19:28:52 +00:00
async def test_state_attributes ( hass : HomeAssistant ) - > None :
2020-09-28 15:35:12 +00:00
""" Test state attributes. """
hass . states . async_set ( " sensor.test " , " 23 " )
tpl = template . Template (
" {{ states.sensor.test.last_changed }} " ,
hass ,
)
assert tpl . async_render ( ) == str ( hass . states . get ( " sensor.test " ) . last_changed )
tpl = template . Template (
" {{ states.sensor.test.object_id }} " ,
hass ,
)
assert tpl . async_render ( ) == hass . states . get ( " sensor.test " ) . object_id
tpl = template . Template (
" {{ states.sensor.test.domain }} " ,
hass ,
)
assert tpl . async_render ( ) == hass . states . get ( " sensor.test " ) . domain
tpl = template . Template (
" {{ states.sensor.test.context.id }} " ,
hass ,
)
assert tpl . async_render ( ) == hass . states . get ( " sensor.test " ) . context . id
tpl = template . Template (
" {{ states.sensor.test.state_with_unit }} " ,
hass ,
)
2020-10-06 22:05:52 +00:00
assert tpl . async_render ( ) == 23
2020-09-28 15:35:12 +00:00
tpl = template . Template (
" {{ states.sensor.test.invalid_prop }} " ,
hass ,
)
assert tpl . async_render ( ) == " "
tpl = template . Template (
" {{ states.sensor.test.invalid_prop.xx }} " ,
hass ,
)
with pytest . raises ( TemplateError ) :
tpl . async_render ( )
2022-11-23 19:28:52 +00:00
async def test_unavailable_states ( hass : HomeAssistant ) - > None :
2020-09-28 15:35:12 +00:00
""" Test watching unavailable states. """
for i in range ( 10 ) :
hass . states . async_set ( f " light.sensor { i } " , " on " )
hass . states . async_set ( " light.unavailable " , " unavailable " )
hass . states . async_set ( " light.unknown " , " unknown " )
hass . states . async_set ( " light.none " , " none " )
tpl = template . Template (
2023-01-26 00:23:53 +00:00
(
" {{ states | selectattr( ' state ' , ' in ' , [ ' unavailable ' , ' unknown ' , ' none ' ]) "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | list | join( ' , ' ) }} "
2023-01-26 00:23:53 +00:00
) ,
2020-09-28 15:35:12 +00:00
hass ,
)
assert tpl . async_render ( ) == " light.none, light.unavailable, light.unknown "
tpl = template . Template (
2023-01-26 00:23:53 +00:00
(
" {{ states.light "
" | selectattr( ' state ' , ' in ' , [ ' unavailable ' , ' unknown ' , ' none ' ]) "
2023-03-31 21:27:55 +00:00
" | sort(attribute= ' entity_id ' ) | map(attribute= ' entity_id ' ) | list "
2023-01-26 00:23:53 +00:00
" | join( ' , ' ) }} "
) ,
2020-09-28 15:35:12 +00:00
hass ,
)
assert tpl . async_render ( ) == " light.none, light.unavailable, light.unknown "
2020-10-06 22:05:52 +00:00
2022-11-23 19:28:52 +00:00
async def test_legacy_templates ( hass : HomeAssistant ) - > None :
2020-10-06 22:05:52 +00:00
""" Test if old template behavior works when legacy templates are enabled. """
hass . states . async_set ( " sensor.temperature " , " 12 " )
assert (
template . Template ( " {{ states.sensor.temperature.state }} " , hass ) . async_render ( )
== 12
)
await async_process_ha_core_config ( hass , { " legacy_templates " : True } )
assert (
template . Template ( " {{ states.sensor.temperature.state }} " , hass ) . async_render ( )
== " 12 "
)
2020-10-26 10:30:58 +00:00
2022-11-23 19:28:52 +00:00
async def test_no_result_parsing ( hass : HomeAssistant ) - > None :
2020-10-26 15:01:09 +00:00
""" Test if templates results are not parsed. """
hass . states . async_set ( " sensor.temperature " , " 12 " )
assert (
template . Template ( " {{ states.sensor.temperature.state }} " , hass ) . async_render (
parse_result = False
)
== " 12 "
)
assert (
template . Template ( " {{ false }} " , hass ) . async_render ( parse_result = False )
== " False "
)
assert (
template . Template ( " {{ [1, 2, 3] }} " , hass ) . async_render ( parse_result = False )
== " [1, 2, 3] "
)
2022-11-23 19:28:52 +00:00
async def test_is_static_still_ast_evals ( hass : HomeAssistant ) - > None :
2021-06-11 11:35:03 +00:00
""" Test is_static still converts to native type. """
2020-10-26 10:30:58 +00:00
tpl = template . Template ( " [1, 2] " , hass )
assert tpl . is_static
assert tpl . async_render ( ) == [ 1 , 2 ]
2022-11-23 19:28:52 +00:00
async def test_result_wrappers ( hass : HomeAssistant ) - > None :
2020-10-26 10:30:58 +00:00
""" Test result wrappers. """
2020-10-27 21:51:58 +00:00
for text , native , orig_type , schema in (
( " [1, 2] " , [ 1 , 2 ] , list , vol . Schema ( [ int ] ) ) ,
( " { 1, 2} " , { 1 , 2 } , set , vol . Schema ( { int } ) ) ,
( " (1, 2) " , ( 1 , 2 ) , tuple , vol . ExactSequence ( [ int , int ] ) ) ,
( ' { " hello " : True} ' , { " hello " : True } , dict , vol . Schema ( { " hello " : bool } ) ) ,
2020-10-26 10:30:58 +00:00
) :
tpl = template . Template ( text , hass )
result = tpl . async_render ( )
2020-10-27 21:51:58 +00:00
assert isinstance ( result , orig_type )
2020-10-26 10:30:58 +00:00
assert isinstance ( result , template . ResultWrapper )
assert result == native
assert result . render_result == text
2020-10-27 21:51:58 +00:00
schema ( result ) # should not raise
2020-10-28 08:11:08 +00:00
# Result with render text stringifies to original text
assert str ( result ) == text
# Result without render text stringifies same as original type
assert str ( template . RESULT_WRAPPERS [ orig_type ] ( native ) ) == str (
orig_type ( native )
)
2020-10-27 22:22:59 +00:00
2022-11-23 19:28:52 +00:00
async def test_parse_result ( hass : HomeAssistant ) - > None :
2020-10-27 22:22:59 +00:00
""" Test parse result. """
for tpl , result in (
( ' {{ " {{ }} " }} ' , " {{ }} " ) ,
( " not-something " , " not-something " ) ,
( " 2a " , " 2a " ) ,
2020-11-13 12:22:29 +00:00
( " 123E5 " , " 123E5 " ) ,
( " 1j " , " 1j " ) ,
( " 1e+100 " , " 1e+100 " ) ,
( " 0xface " , " 0xface " ) ,
( " 123 " , 123 ) ,
2020-11-25 15:10:33 +00:00
( " 10 " , 10 ) ,
2020-11-13 12:22:29 +00:00
( " 123.0 " , 123.0 ) ,
( " .5 " , 0.5 ) ,
2020-11-25 15:10:33 +00:00
( " 0.5 " , 0.5 ) ,
2020-11-13 12:22:29 +00:00
( " -1 " , - 1 ) ,
( " -1.0 " , - 1.0 ) ,
( " +1 " , 1 ) ,
( " 5. " , 5.0 ) ,
2020-11-25 15:10:33 +00:00
( " 123_123_123 " , " 123_123_123 " ) ,
# ("+48100200300", "+48100200300"), # phone number
( " 010 " , " 010 " ) ,
( " 0011101.00100001010001 " , " 0011101.00100001010001 " ) ,
2020-10-27 22:22:59 +00:00
) :
assert template . Template ( tpl , hass ) . async_render ( ) == result
2021-03-20 14:16:04 +00:00
2023-09-06 08:03:35 +00:00
@pytest.mark.parametrize (
" template_string " ,
[
" {{ no_such_variable }} " ,
" {{ no_such_variable and True }} " ,
" {{ no_such_variable | join( ' , ' ) }} " ,
] ,
)
async def test_undefined_symbol_warnings (
hass : HomeAssistant ,
caplog : pytest . LogCaptureFixture ,
template_string : str ,
2023-02-20 10:42:56 +00:00
) - > None :
2021-03-20 14:16:04 +00:00
""" Test a warning is logged on undefined variables. """
2023-09-06 08:03:35 +00:00
tpl = template . Template ( template_string , hass )
2021-03-20 14:16:04 +00:00
assert tpl . async_render ( ) == " "
2021-04-06 19:11:42 +00:00
assert (
2023-01-26 00:23:53 +00:00
" Template variable warning: ' no_such_variable ' is undefined when rendering "
2023-09-06 08:03:35 +00:00
f " ' { template_string } ' " in caplog . text
2021-04-06 19:11:42 +00:00
)
2022-06-24 21:28:26 +00:00
2022-11-23 19:28:52 +00:00
async def test_template_states_blocks_setitem ( hass : HomeAssistant ) - > None :
2022-06-24 21:28:26 +00:00
""" Test we cannot setitem on TemplateStates. """
hass . states . async_set ( " light.new " , STATE_ON )
state = hass . states . get ( " light.new " )
template_state = template . TemplateState ( hass , state , True )
with pytest . raises ( RuntimeError ) :
template_state [ " any " ] = " any "
2022-06-25 16:19:11 +00:00
2022-11-23 19:28:52 +00:00
async def test_template_states_can_serialize ( hass : HomeAssistant ) - > None :
2022-06-25 16:19:11 +00:00
""" Test TemplateState is serializable. """
hass . states . async_set ( " light.new " , STATE_ON )
state = hass . states . get ( " light.new " )
template_state = template . TemplateState ( hass , state , True )
assert template_state . as_dict ( ) is template_state . as_dict ( )
assert json_dumps ( template_state ) == json_dumps ( template_state )
2023-01-25 10:51:47 +00:00
@pytest.mark.parametrize (
2023-02-15 13:09:50 +00:00
( " seq " , " value " , " expected " ) ,
2023-01-25 10:51:47 +00:00
[
( [ 0 ] , 0 , True ) ,
( [ 1 ] , 0 , False ) ,
( [ False ] , 0 , True ) ,
( [ True ] , 0 , False ) ,
( [ 0 ] , [ 0 ] , False ) ,
( [ " toto " , 1 ] , " toto " , True ) ,
( [ " toto " , 1 ] , " tata " , False ) ,
( [ ] , 0 , False ) ,
( [ ] , None , False ) ,
] ,
)
2023-02-20 10:42:56 +00:00
def test_contains ( hass : HomeAssistant , seq , value , expected ) - > None :
2023-01-25 10:51:47 +00:00
""" Test contains. """
assert (
template . Template ( " {{ seq | contains(value) }} " , hass ) . async_render (
{ " seq " : seq , " value " : value }
)
== expected
)
assert (
template . Template ( " {{ seq is contains(value) }} " , hass ) . async_render (
{ " seq " : seq , " value " : value }
)
== expected
)
2023-03-08 20:50:34 +00:00
async def test_render_to_info_with_exception ( hass : HomeAssistant ) - > None :
""" Test info is still available if the template has an exception. """
hass . states . async_set ( " test_domain.object " , " dog " )
info = render_to_info ( hass , ' {{ states( " test_domain.object " ) | float }} ' )
with pytest . raises ( TemplateError , match = " no default was specified " ) :
info . result ( )
assert info . all_states is False
assert info . entities == { " test_domain.object " }
2023-04-03 00:51:25 +00:00
async def test_lru_increases_with_many_entities ( hass : HomeAssistant ) - > None :
""" Test that the template internal LRU cache increases with many entities. """
# We do not actually want to record 4096 entities so we mock the entity count
2023-07-05 12:00:37 +00:00
mock_entity_count = 16
2023-04-03 00:51:25 +00:00
assert template . CACHED_TEMPLATE_LRU . get_size ( ) == template . CACHED_TEMPLATE_STATES
assert (
template . CACHED_TEMPLATE_NO_COLLECT_LRU . get_size ( )
== template . CACHED_TEMPLATE_STATES
)
2023-07-05 12:00:37 +00:00
template . CACHED_TEMPLATE_LRU . set_size ( 8 )
template . CACHED_TEMPLATE_NO_COLLECT_LRU . set_size ( 8 )
2023-04-03 00:51:25 +00:00
template . async_setup ( hass )
2023-07-05 12:00:37 +00:00
for i in range ( mock_entity_count ) :
hass . states . async_set ( f " sensor.sensor { i } " , " on " )
async_fire_time_changed ( hass , dt_util . utcnow ( ) + timedelta ( minutes = 10 ) )
await hass . async_block_till_done ( )
2023-04-03 00:51:25 +00:00
assert template . CACHED_TEMPLATE_LRU . get_size ( ) == int (
round ( mock_entity_count * template . ENTITY_COUNT_GROWTH_FACTOR )
)
assert template . CACHED_TEMPLATE_NO_COLLECT_LRU . get_size ( ) == int (
round ( mock_entity_count * template . ENTITY_COUNT_GROWTH_FACTOR )
)
await hass . async_stop ( )
2023-07-05 12:00:37 +00:00
for i in range ( mock_entity_count ) :
hass . states . async_set ( f " sensor.sensor_add_ { i } " , " on " )
async_fire_time_changed ( hass , dt_util . utcnow ( ) + timedelta ( minutes = 20 ) )
await hass . async_block_till_done ( )
2023-04-03 00:51:25 +00:00
assert template . CACHED_TEMPLATE_LRU . get_size ( ) == int (
round ( mock_entity_count * template . ENTITY_COUNT_GROWTH_FACTOR )
)
assert template . CACHED_TEMPLATE_NO_COLLECT_LRU . get_size ( ) == int (
round ( mock_entity_count * template . ENTITY_COUNT_GROWTH_FACTOR )
)