mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 06:06:33 +00:00
[api] Fix compilation error with char* lambdas in HomeAssistant services (#9638)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
cdeed7afa7
commit
21e66b76e4
@ -16,6 +16,9 @@ template<typename... X> class TemplatableStringValue : public TemplatableValue<s
|
|||||||
template<typename T> static std::string value_to_string(T &&val) { return to_string(std::forward<T>(val)); }
|
template<typename T> static std::string value_to_string(T &&val) { return to_string(std::forward<T>(val)); }
|
||||||
|
|
||||||
// Overloads for string types - needed because std::to_string doesn't support them
|
// Overloads for string types - needed because std::to_string doesn't support them
|
||||||
|
static std::string value_to_string(char *val) {
|
||||||
|
return val ? std::string(val) : std::string();
|
||||||
|
} // For lambdas returning char* (e.g., itoa)
|
||||||
static std::string value_to_string(const char *val) { return std::string(val); } // For lambdas returning .c_str()
|
static std::string value_to_string(const char *val) { return std::string(val); } // For lambdas returning .c_str()
|
||||||
static std::string value_to_string(const std::string &val) { return val; }
|
static std::string value_to_string(const std::string &val) { return val; }
|
||||||
static std::string value_to_string(std::string &&val) { return std::move(val); }
|
static std::string value_to_string(std::string &&val) { return std::move(val); }
|
||||||
|
@ -60,5 +60,28 @@ api:
|
|||||||
data:
|
data:
|
||||||
value: !lambda 'return input_float;'
|
value: !lambda 'return input_float;'
|
||||||
|
|
||||||
|
# Service that tests char* lambda functionality (e.g., from itoa or sprintf)
|
||||||
|
- action: test_char_ptr_lambda
|
||||||
|
variables:
|
||||||
|
input_number: int
|
||||||
|
input_string: string
|
||||||
|
then:
|
||||||
|
# Log the input to verify service was called
|
||||||
|
- logger.log:
|
||||||
|
format: "Service called with number for char* test: %d"
|
||||||
|
args: [input_number]
|
||||||
|
|
||||||
|
# Test that char* lambdas work correctly
|
||||||
|
# This would fail in issue #9628 with "invalid conversion from 'char*' to 'long long unsigned int'"
|
||||||
|
- homeassistant.event:
|
||||||
|
event: esphome.test_char_ptr_lambda
|
||||||
|
data:
|
||||||
|
# Test snprintf returning char*
|
||||||
|
decimal_value: !lambda 'static char buffer[20]; snprintf(buffer, sizeof(buffer), "%d", input_number); return buffer;'
|
||||||
|
# Test strdup returning char* (dynamically allocated)
|
||||||
|
string_copy: !lambda 'return strdup(input_string.c_str());'
|
||||||
|
# Test string literal (const char*)
|
||||||
|
literal: !lambda 'return "test literal";'
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
level: DEBUG
|
level: DEBUG
|
||||||
|
@ -19,15 +19,17 @@ async def test_api_string_lambda(
|
|||||||
"""Test TemplatableStringValue works with lambdas that return different types."""
|
"""Test TemplatableStringValue works with lambdas that return different types."""
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
# Track log messages for all three service calls
|
# Track log messages for all four service calls
|
||||||
string_called_future = loop.create_future()
|
string_called_future = loop.create_future()
|
||||||
int_called_future = loop.create_future()
|
int_called_future = loop.create_future()
|
||||||
float_called_future = loop.create_future()
|
float_called_future = loop.create_future()
|
||||||
|
char_ptr_called_future = loop.create_future()
|
||||||
|
|
||||||
# Patterns to match in logs - confirms the lambdas compiled and executed
|
# Patterns to match in logs - confirms the lambdas compiled and executed
|
||||||
string_pattern = re.compile(r"Service called with string: STRING_FROM_LAMBDA")
|
string_pattern = re.compile(r"Service called with string: STRING_FROM_LAMBDA")
|
||||||
int_pattern = re.compile(r"Service called with int: 42")
|
int_pattern = re.compile(r"Service called with int: 42")
|
||||||
float_pattern = re.compile(r"Service called with float: 3\.14")
|
float_pattern = re.compile(r"Service called with float: 3\.14")
|
||||||
|
char_ptr_pattern = re.compile(r"Service called with number for char\* test: 123")
|
||||||
|
|
||||||
def check_output(line: str) -> None:
|
def check_output(line: str) -> None:
|
||||||
"""Check log output for expected messages."""
|
"""Check log output for expected messages."""
|
||||||
@ -37,6 +39,8 @@ async def test_api_string_lambda(
|
|||||||
int_called_future.set_result(True)
|
int_called_future.set_result(True)
|
||||||
if not float_called_future.done() and float_pattern.search(line):
|
if not float_called_future.done() and float_pattern.search(line):
|
||||||
float_called_future.set_result(True)
|
float_called_future.set_result(True)
|
||||||
|
if not char_ptr_called_future.done() and char_ptr_pattern.search(line):
|
||||||
|
char_ptr_called_future.set_result(True)
|
||||||
|
|
||||||
# Run with log monitoring
|
# Run with log monitoring
|
||||||
async with (
|
async with (
|
||||||
@ -65,17 +69,28 @@ async def test_api_string_lambda(
|
|||||||
)
|
)
|
||||||
assert float_service is not None, "test_float_lambda service not found"
|
assert float_service is not None, "test_float_lambda service not found"
|
||||||
|
|
||||||
# Execute all three services to test different lambda return types
|
char_ptr_service = next(
|
||||||
|
(s for s in services if s.name == "test_char_ptr_lambda"), None
|
||||||
|
)
|
||||||
|
assert char_ptr_service is not None, "test_char_ptr_lambda service not found"
|
||||||
|
|
||||||
|
# Execute all four services to test different lambda return types
|
||||||
client.execute_service(string_service, {"input_string": "STRING_FROM_LAMBDA"})
|
client.execute_service(string_service, {"input_string": "STRING_FROM_LAMBDA"})
|
||||||
client.execute_service(int_service, {"input_number": 42})
|
client.execute_service(int_service, {"input_number": 42})
|
||||||
client.execute_service(float_service, {"input_float": 3.14})
|
client.execute_service(float_service, {"input_float": 3.14})
|
||||||
|
client.execute_service(
|
||||||
|
char_ptr_service, {"input_number": 123, "input_string": "test_string"}
|
||||||
|
)
|
||||||
|
|
||||||
# Wait for all service log messages
|
# Wait for all service log messages
|
||||||
# This confirms the lambdas compiled successfully and executed
|
# This confirms the lambdas compiled successfully and executed
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(
|
await asyncio.wait_for(
|
||||||
asyncio.gather(
|
asyncio.gather(
|
||||||
string_called_future, int_called_future, float_called_future
|
string_called_future,
|
||||||
|
int_called_future,
|
||||||
|
float_called_future,
|
||||||
|
char_ptr_called_future,
|
||||||
),
|
),
|
||||||
timeout=5.0,
|
timeout=5.0,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user