mirror of
https://github.com/esphome/esphome.git
synced 2026-09-21 03:58:41 +00:00
[automation] Eliminate trigger trampolines with deduplicated forwarder structs (#15174)
This commit is contained in:
@@ -5,7 +5,13 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.automation import has_non_synchronous_actions
|
||||
from esphome.automation import (
|
||||
TriggerForwarder,
|
||||
TriggerOnFalseForwarder,
|
||||
TriggerOnTrueForwarder,
|
||||
has_non_synchronous_actions,
|
||||
)
|
||||
from esphome.cpp_generator import MockObj, RawExpression
|
||||
from esphome.util import RegistryEntry
|
||||
|
||||
|
||||
@@ -175,3 +181,76 @@ def test_has_non_synchronous_actions_dict_input(
|
||||
"""Direct dict input (single action)."""
|
||||
assert has_non_synchronous_actions({"delay": "1s"}) is True
|
||||
assert has_non_synchronous_actions({"logger.log": "hello"}) is False
|
||||
|
||||
|
||||
def _build_forwarder(
|
||||
automation_name: str,
|
||||
args: list[tuple[str, str]],
|
||||
forwarder: MockObj | None = None,
|
||||
) -> str:
|
||||
"""Build a trigger forwarder expression the same way build_callback_automation does.
|
||||
|
||||
Mirrors the forwarder selection logic in automation.build_callback_automation.
|
||||
"""
|
||||
import esphome.codegen as cg
|
||||
|
||||
obj = MockObj(automation_name, "->")
|
||||
if forwarder is None:
|
||||
arg_types = [RawExpression(t) for t, _ in args]
|
||||
templ = (
|
||||
cg.TemplateArguments(*arg_types) if arg_types else cg.TemplateArguments()
|
||||
)
|
||||
forwarder = TriggerForwarder.template(templ)
|
||||
return f"{forwarder}{{{obj}}}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_no_args() -> None:
|
||||
"""Button on_press: TriggerForwarder<> with no args."""
|
||||
result = _build_forwarder("auto_1", [])
|
||||
assert result == "TriggerForwarder<>{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_single_float_arg() -> None:
|
||||
"""Sensor on_value: TriggerForwarder<float>."""
|
||||
result = _build_forwarder("auto_1", [("float", "x")])
|
||||
assert result == "TriggerForwarder<float>{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_single_bool_arg() -> None:
|
||||
"""Switch on_state: TriggerForwarder<bool>."""
|
||||
result = _build_forwarder("auto_1", [("bool", "x")])
|
||||
assert result == "TriggerForwarder<bool>{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_on_true() -> None:
|
||||
"""Binary_sensor on_press / switch on_turn_on: TriggerOnTrueForwarder."""
|
||||
result = _build_forwarder("auto_1", [], forwarder=TriggerOnTrueForwarder)
|
||||
assert result == "TriggerOnTrueForwarder{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_on_false() -> None:
|
||||
"""Binary_sensor on_release / switch on_turn_off: TriggerOnFalseForwarder."""
|
||||
result = _build_forwarder("auto_1", [], forwarder=TriggerOnFalseForwarder)
|
||||
assert result == "TriggerOnFalseForwarder{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_multiple_args() -> None:
|
||||
"""Binary_sensor on_state_change: TriggerForwarder with two args."""
|
||||
result = _build_forwarder(
|
||||
"auto_1",
|
||||
[("optional<bool>", "x_previous"), ("optional<bool>", "x")],
|
||||
)
|
||||
assert result == "TriggerForwarder<optional<bool>, optional<bool>>{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_string_arg() -> None:
|
||||
"""Text_sensor on_value: TriggerForwarder<std::string>."""
|
||||
result = _build_forwarder("auto_1", [("std::string", "x")])
|
||||
assert result == "TriggerForwarder<std::string>{auto_1}"
|
||||
|
||||
|
||||
def test_trigger_forwarder_custom_type() -> None:
|
||||
"""Custom forwarder type passed directly."""
|
||||
custom = MockObj("MyForwarder", "")
|
||||
result = _build_forwarder("auto_1", [], forwarder=custom)
|
||||
assert result == "MyForwarder{auto_1}"
|
||||
|
||||
Reference in New Issue
Block a user