mirror of
https://github.com/esphome/esphome.git
synced 2026-05-30 07:16:11 +08:00
[core] Merge set_name + set_entity_strings into configure_entity_ (#14444)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,8 @@ static const char *const TAG = "entity_base";
|
||||
|
||||
// Entity Name
|
||||
const StringRef &EntityBase::get_name() const { return this->name_; }
|
||||
void EntityBase::set_name(const char *name) { this->set_name(name, 0); }
|
||||
void EntityBase::set_name(const char *name, uint32_t object_id_hash) {
|
||||
|
||||
void EntityBase::configure_entity_(const char *name, uint32_t object_id_hash, uint32_t entity_strings_packed) {
|
||||
this->name_ = StringRef(name);
|
||||
if (this->name_.empty()) {
|
||||
#ifdef USE_DEVICES
|
||||
@@ -44,6 +44,17 @@ void EntityBase::set_name(const char *name, uint32_t object_id_hash) {
|
||||
this->calc_object_id_();
|
||||
}
|
||||
}
|
||||
// Unpack entity string table indices.
|
||||
// Packed: [23..16] icon | [15..8] UoM | [7..0] device_class (each 8 bits)
|
||||
#ifdef USE_ENTITY_DEVICE_CLASS
|
||||
this->device_class_idx_ = entity_strings_packed & 0xFF;
|
||||
#endif
|
||||
#ifdef USE_ENTITY_UNIT_OF_MEASUREMENT
|
||||
this->uom_idx_ = (entity_strings_packed >> 8) & 0xFF;
|
||||
#endif
|
||||
#ifdef USE_ENTITY_ICON
|
||||
this->icon_idx_ = (entity_strings_packed >> 16) & 0xFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Weak default lookup functions — overridden by generated code in main.cpp
|
||||
|
||||
+11
-19
@@ -12,6 +12,10 @@
|
||||
#include "device.h"
|
||||
#endif
|
||||
|
||||
// Forward declarations for friend access from codegen-generated setup()
|
||||
void setup(); // NOLINT(readability-redundant-declaration) - may be declared in Arduino.h
|
||||
void original_setup(); // NOLINT(readability-redundant-declaration) - used by cpp unit tests
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// Extern lookup functions for entity string tables.
|
||||
@@ -54,12 +58,8 @@ enum EntityCategory : uint8_t {
|
||||
// The generic Entity base class that provides an interface common to all Entities.
|
||||
class EntityBase {
|
||||
public:
|
||||
// Get/set the name of this Entity
|
||||
// Get the name of this Entity
|
||||
const StringRef &get_name() const;
|
||||
void set_name(const char *name);
|
||||
/// Set name with pre-computed object_id hash (avoids runtime hash calculation)
|
||||
/// Use hash=0 for dynamic names that need runtime calculation
|
||||
void set_name(const char *name, uint32_t object_id_hash);
|
||||
|
||||
// Get whether this Entity has its own name or it should use the device friendly_name.
|
||||
bool has_own_name() const { return this->flags_.has_own_name; }
|
||||
@@ -104,20 +104,6 @@ class EntityBase {
|
||||
this->flags_.entity_category = static_cast<uint8_t>(entity_category);
|
||||
}
|
||||
|
||||
// Set entity string table indices — one call per entity from codegen.
|
||||
// Packed: [23..16] icon | [15..8] UoM | [7..0] device_class (each 8 bits)
|
||||
void set_entity_strings([[maybe_unused]] uint32_t packed) {
|
||||
#ifdef USE_ENTITY_DEVICE_CLASS
|
||||
this->device_class_idx_ = packed & 0xFF;
|
||||
#endif
|
||||
#ifdef USE_ENTITY_UNIT_OF_MEASUREMENT
|
||||
this->uom_idx_ = (packed >> 8) & 0xFF;
|
||||
#endif
|
||||
#ifdef USE_ENTITY_ICON
|
||||
this->icon_idx_ = (packed >> 16) & 0xFF;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get this entity's device class into a stack buffer.
|
||||
// On non-ESP8266: returns pointer to PROGMEM string directly (buffer unused).
|
||||
// On ESP8266: copies from PROGMEM to buffer, returns buffer pointer.
|
||||
@@ -239,6 +225,12 @@ class EntityBase {
|
||||
}
|
||||
|
||||
protected:
|
||||
friend void ::setup();
|
||||
friend void ::original_setup();
|
||||
|
||||
/// Combined entity setup from codegen: set name, object_id hash, and entity string indices.
|
||||
void configure_entity_(const char *name, uint32_t object_id_hash, uint32_t entity_strings_packed);
|
||||
|
||||
/// Non-template helper for make_entity_preference() to avoid code bloat.
|
||||
/// When preference hash algorithm changes, migration logic goes here.
|
||||
ESPPreferenceObject make_entity_preference_(size_t size, uint32_t version);
|
||||
|
||||
@@ -31,8 +31,10 @@ DOMAIN = "entity_string_pool"
|
||||
_KEY_DC_IDX = "_entity_dc_idx"
|
||||
_KEY_UOM_IDX = "_entity_uom_idx"
|
||||
_KEY_ICON_IDX = "_entity_icon_idx"
|
||||
_KEY_ENTITY_NAME = "_entity_name"
|
||||
_KEY_OBJECT_ID_HASH = "_entity_object_id_hash"
|
||||
|
||||
# Bit layout for set_entity_strings(packed) — must match C++ setter in entity_base.h:
|
||||
# Bit layout for entity_strings_packed in configure_entity_() — must match C++ in entity_base.h:
|
||||
# [23..16] icon (8 bits) | [15..8] UoM (8 bits) | [7..0] device_class (8 bits)
|
||||
_DC_SHIFT = 0
|
||||
_UOM_SHIFT = 8
|
||||
@@ -219,17 +221,18 @@ def setup_unit_of_measurement(config: ConfigType) -> None:
|
||||
|
||||
|
||||
def finalize_entity_strings(var: MockObj, config: ConfigType) -> None:
|
||||
"""Emit a single set_entity_strings() call with all packed indices.
|
||||
"""Emit a single configure_entity_() call with name, hash, and packed string indices.
|
||||
|
||||
Call this at the end of each component's setup function, after
|
||||
setup_entity() and any register_device_class/register_unit_of_measurement calls.
|
||||
"""
|
||||
entity_name = config[_KEY_ENTITY_NAME]
|
||||
object_id_hash = config[_KEY_OBJECT_ID_HASH]
|
||||
dc_idx = config.get(_KEY_DC_IDX, 0)
|
||||
uom_idx = config.get(_KEY_UOM_IDX, 0)
|
||||
icon_idx = config.get(_KEY_ICON_IDX, 0)
|
||||
packed = (dc_idx << _DC_SHIFT) | (uom_idx << _UOM_SHIFT) | (icon_idx << _ICON_SHIFT)
|
||||
if packed != 0:
|
||||
add(var.set_entity_strings(packed))
|
||||
add(var.configure_entity_(entity_name, object_id_hash, packed))
|
||||
|
||||
|
||||
def get_base_entity_object_id(
|
||||
@@ -331,13 +334,15 @@ async def _setup_entity_impl(var: MockObj, config: ConfigType, platform: str) ->
|
||||
device: MockObj = await get_variable(device_id_obj)
|
||||
add(var.set_device(device))
|
||||
|
||||
# Set the entity name with pre-computed object_id hash
|
||||
# Pre-compute entity name and object_id hash for configure_entity_()
|
||||
# which is emitted later by finalize_entity_strings().
|
||||
# For named entities: pre-compute hash from entity name
|
||||
# For empty-name entities: pass 0, C++ calculates hash at runtime from
|
||||
# device name, friendly_name, or app name (bug-for-bug compatibility)
|
||||
entity_name = config[CONF_NAME]
|
||||
object_id_hash = fnv1_hash_object_id(entity_name) if entity_name else 0
|
||||
add(var.set_name(entity_name, object_id_hash))
|
||||
config[_KEY_ENTITY_NAME] = entity_name
|
||||
config[_KEY_OBJECT_ID_HASH] = object_id_hash
|
||||
# Only set disabled_by_default if True (default is False)
|
||||
if config[CONF_DISABLED_BY_DEFAULT]:
|
||||
add(var.set_disabled_by_default(True))
|
||||
|
||||
@@ -29,7 +29,7 @@ def test_binary_sensor_sets_mandatory_fields(generate_main):
|
||||
)
|
||||
|
||||
# Then
|
||||
assert 'bs_1->set_name("test bs1",' in main_cpp
|
||||
assert 'bs_1->configure_entity_("test bs1",' in main_cpp
|
||||
assert "bs_1->set_pin(" in main_cpp
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ def test_button_sets_mandatory_fields(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/button/test_button.yaml")
|
||||
|
||||
# Then
|
||||
assert 'wol_1->set_name("wol_test_1",' in main_cpp
|
||||
assert 'wol_1->configure_entity_("wol_test_1",' in main_cpp
|
||||
assert "wol_2->set_macaddr(18, 52, 86, 120, 144, 171);" in main_cpp
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
"""Tests for the sensor component."""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def _extract_packed_value(main_cpp, var_name):
|
||||
"""Extract the third (packed) argument from a configure_entity_ call."""
|
||||
pattern = rf"{re.escape(var_name)}->configure_entity_\([^,]+,\s*\w+,\s*(\d+)\)"
|
||||
match = re.search(pattern, main_cpp)
|
||||
assert match, f"configure_entity_ call not found for {var_name}"
|
||||
return int(match.group(1))
|
||||
|
||||
|
||||
def test_sensor_device_class_set(generate_main):
|
||||
"""
|
||||
@@ -10,5 +20,6 @@ def test_sensor_device_class_set(generate_main):
|
||||
# When
|
||||
main_cpp = generate_main("tests/component_tests/sensor/test_sensor.yaml")
|
||||
|
||||
# Then
|
||||
assert "s_1->set_entity_strings(" in main_cpp
|
||||
# Then: device_class: voltage means packed value must be non-zero
|
||||
packed = _extract_packed_value(main_cpp, "s_1")
|
||||
assert packed != 0
|
||||
|
||||
@@ -25,7 +25,7 @@ def test_text_sets_mandatory_fields(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/text/test_text.yaml")
|
||||
|
||||
# Then
|
||||
assert 'it_1->set_name("test 1 text",' in main_cpp
|
||||
assert 'it_1->configure_entity_("test 1 text",' in main_cpp
|
||||
|
||||
|
||||
def test_text_config_value_internal_set(generate_main):
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
"""Tests for the text sensor component."""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def _extract_packed_value(main_cpp, var_name):
|
||||
"""Extract the third (packed) argument from a configure_entity_ call."""
|
||||
pattern = rf"{re.escape(var_name)}->configure_entity_\([^,]+,\s*\w+,\s*(\d+)\)"
|
||||
match = re.search(pattern, main_cpp)
|
||||
assert match, f"configure_entity_ call not found for {var_name}"
|
||||
return int(match.group(1))
|
||||
|
||||
|
||||
def test_text_sensor_is_setup(generate_main):
|
||||
"""
|
||||
@@ -25,9 +35,9 @@ def test_text_sensor_sets_mandatory_fields(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/text_sensor/test_text_sensor.yaml")
|
||||
|
||||
# Then
|
||||
assert 'ts_1->set_name("Template Text Sensor 1",' in main_cpp
|
||||
assert 'ts_2->set_name("Template Text Sensor 2",' in main_cpp
|
||||
assert 'ts_3->set_name("Template Text Sensor 3",' in main_cpp
|
||||
assert 'ts_1->configure_entity_("Template Text Sensor 1",' in main_cpp
|
||||
assert 'ts_2->configure_entity_("Template Text Sensor 2",' in main_cpp
|
||||
assert 'ts_3->configure_entity_("Template Text Sensor 3",' in main_cpp
|
||||
|
||||
|
||||
def test_text_sensor_config_value_internal_set(generate_main):
|
||||
@@ -53,6 +63,9 @@ def test_text_sensor_device_class_set(generate_main):
|
||||
# When
|
||||
main_cpp = generate_main("tests/component_tests/text_sensor/test_text_sensor.yaml")
|
||||
|
||||
# Then
|
||||
assert "ts_2->set_entity_strings(" in main_cpp
|
||||
assert "ts_3->set_entity_strings(" in main_cpp
|
||||
# Then: ts_2 has device_class: timestamp, ts_3 has device_class: date
|
||||
# so their packed values must be non-zero
|
||||
packed_ts_2 = _extract_packed_value(main_cpp, "ts_2")
|
||||
assert packed_ts_2 != 0
|
||||
packed_ts_3 = _extract_packed_value(main_cpp, "ts_3")
|
||||
assert packed_ts_3 != 0
|
||||
|
||||
@@ -32,9 +32,11 @@ from esphome.helpers import sanitize, snake_case
|
||||
|
||||
from .common import load_config_from_fixture
|
||||
|
||||
# Pre-compiled regex pattern for extracting names from set_name calls
|
||||
# Matches: .set_name("name", hash) or .set_name("name")
|
||||
SET_NAME_PATTERN = re.compile(r'\.set_name\(["\']([^"\']*)["\']')
|
||||
# Pre-compiled regex pattern for extracting names from configure_entity_/set_name calls
|
||||
# Matches: .configure_entity_("name", ...) or .set_name("name", ...)
|
||||
ENTITY_NAME_PATTERN = re.compile(
|
||||
r'\.(?:configure_entity_|set_name)\(["\']([^"\']*)["\']'
|
||||
)
|
||||
|
||||
FIXTURES_DIR = Path(__file__).parent.parent / "fixtures" / "core" / "entity_helpers"
|
||||
|
||||
@@ -276,15 +278,23 @@ def setup_test_environment() -> Generator[list[str], None, None]:
|
||||
entity_helpers.add = original_add
|
||||
|
||||
|
||||
def extract_object_id_from_expressions(expressions: list[str]) -> str | None:
|
||||
"""Extract the object ID that would be computed from set_name calls.
|
||||
def extract_object_id_from_config(config: dict[str, Any]) -> str | None:
|
||||
"""Extract the object ID from config keys set by _setup_entity_impl."""
|
||||
name = config.get("_entity_name")
|
||||
if name is None:
|
||||
return None
|
||||
if name:
|
||||
return sanitize(snake_case(name))
|
||||
# Empty name - fall back to friendly_name or device name
|
||||
if CORE.friendly_name:
|
||||
return sanitize(snake_case(CORE.friendly_name))
|
||||
return sanitize(snake_case(CORE.name)) if CORE.name else None
|
||||
|
||||
Since object_id is now computed from the name (via snake_case + sanitize),
|
||||
we extract the name from set_name() calls and compute the expected object_id.
|
||||
For empty names, we fall back to CORE.friendly_name or CORE.name.
|
||||
"""
|
||||
|
||||
def extract_object_id_from_expressions(expressions: list[str]) -> str | None:
|
||||
"""Extract the object ID from configure_entity_() calls in generated expressions."""
|
||||
for expr in expressions:
|
||||
if match := SET_NAME_PATTERN.search(expr):
|
||||
if match := ENTITY_NAME_PATTERN.search(expr):
|
||||
name = match.group(1)
|
||||
if name:
|
||||
return sanitize(snake_case(name))
|
||||
@@ -299,8 +309,6 @@ def extract_object_id_from_expressions(expressions: list[str]) -> str | None:
|
||||
async def test_setup_entity_no_duplicates(setup_test_environment: list[str]) -> None:
|
||||
"""Test setup_entity with unique names."""
|
||||
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
# Create mock entities
|
||||
var1 = MockObj("sensor1")
|
||||
var2 = MockObj("sensor2")
|
||||
@@ -312,13 +320,10 @@ async def test_setup_entity_no_duplicates(setup_test_environment: list[str]) ->
|
||||
}
|
||||
await _setup_entity_impl(var1, config1, "sensor")
|
||||
|
||||
# Get object ID from first entity
|
||||
object_id1 = extract_object_id_from_expressions(added_expressions)
|
||||
# Get object ID from first entity (stored in config, emitted later by finalize)
|
||||
object_id1 = extract_object_id_from_config(config1)
|
||||
assert object_id1 == "temperature"
|
||||
|
||||
# Clear for next entity
|
||||
added_expressions.clear()
|
||||
|
||||
# Set up second entity with different name
|
||||
config2 = {
|
||||
CONF_NAME: "Humidity",
|
||||
@@ -327,7 +332,7 @@ async def test_setup_entity_no_duplicates(setup_test_environment: list[str]) ->
|
||||
await _setup_entity_impl(var2, config2, "sensor")
|
||||
|
||||
# Get object ID from second entity
|
||||
object_id2 = extract_object_id_from_expressions(added_expressions)
|
||||
object_id2 = extract_object_id_from_config(config2)
|
||||
assert object_id2 == "humidity"
|
||||
|
||||
|
||||
@@ -337,8 +342,6 @@ async def test_setup_entity_different_platforms(
|
||||
) -> None:
|
||||
"""Test that same name on different platforms doesn't conflict."""
|
||||
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
# Create mock entities
|
||||
sensor = MockObj("sensor1")
|
||||
binary_sensor = MockObj("binary_sensor1")
|
||||
@@ -356,15 +359,11 @@ async def test_setup_entity_different_platforms(
|
||||
(text_sensor, "text_sensor"),
|
||||
]
|
||||
|
||||
object_ids: list[str] = []
|
||||
for var, platform in platforms:
|
||||
added_expressions.clear()
|
||||
await _setup_entity_impl(var, config, platform)
|
||||
object_id = extract_object_id_from_expressions(added_expressions)
|
||||
object_ids.append(object_id)
|
||||
|
||||
# All should get base object ID without suffix
|
||||
assert all(obj_id == "status" for obj_id in object_ids)
|
||||
# All should get the same object ID (name stored in config, not platform-specific)
|
||||
assert extract_object_id_from_config(config) == "status"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -389,7 +388,6 @@ async def test_setup_entity_with_devices(
|
||||
setup_test_environment: list[str], mock_get_variable: dict[ID, MockObj]
|
||||
) -> None:
|
||||
"""Test that same name on different devices doesn't conflict."""
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
# Create mock devices
|
||||
device1_id = ID("device1", type="Device")
|
||||
@@ -418,24 +416,18 @@ async def test_setup_entity_with_devices(
|
||||
}
|
||||
|
||||
# Get object IDs
|
||||
object_ids: list[str] = []
|
||||
for var, config in [(sensor1, config1), (sensor2, config2)]:
|
||||
added_expressions.clear()
|
||||
await _setup_entity_impl(var, config, "sensor")
|
||||
object_id = extract_object_id_from_expressions(added_expressions)
|
||||
object_ids.append(object_id)
|
||||
|
||||
# Both should get base object ID without suffix (different devices)
|
||||
assert object_ids[0] == "temperature"
|
||||
assert object_ids[1] == "temperature"
|
||||
assert extract_object_id_from_config(config1) == "temperature"
|
||||
assert extract_object_id_from_config(config2) == "temperature"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_setup_entity_empty_name(setup_test_environment: list[str]) -> None:
|
||||
"""Test setup_entity with empty entity name."""
|
||||
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
var = MockObj("sensor1")
|
||||
|
||||
config = {
|
||||
@@ -445,7 +437,7 @@ async def test_setup_entity_empty_name(setup_test_environment: list[str]) -> Non
|
||||
|
||||
await _setup_entity_impl(var, config, "sensor")
|
||||
|
||||
object_id = extract_object_id_from_expressions(added_expressions)
|
||||
object_id = extract_object_id_from_config(config)
|
||||
# Should use friendly name
|
||||
assert object_id == "test_device"
|
||||
|
||||
@@ -456,8 +448,6 @@ async def test_setup_entity_special_characters(
|
||||
) -> None:
|
||||
"""Test setup_entity with names containing special characters."""
|
||||
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
var = MockObj("sensor1")
|
||||
|
||||
config = {
|
||||
@@ -466,7 +456,7 @@ async def test_setup_entity_special_characters(
|
||||
}
|
||||
|
||||
await _setup_entity_impl(var, config, "sensor")
|
||||
object_id = extract_object_id_from_expressions(added_expressions)
|
||||
object_id = extract_object_id_from_config(config)
|
||||
|
||||
# Special characters should be sanitized
|
||||
assert object_id == "temperature_sensor_"
|
||||
@@ -476,8 +466,6 @@ async def test_setup_entity_special_characters(
|
||||
async def test_setup_entity_with_icon(setup_test_environment: list[str]) -> None:
|
||||
"""Test setup_entity sets icon correctly."""
|
||||
|
||||
setup_test_environment # noqa: F841 - fixture initializes CORE state
|
||||
|
||||
var = MockObj("sensor1")
|
||||
|
||||
config = {
|
||||
@@ -800,10 +788,9 @@ async def test_setup_entity_empty_name_with_device(
|
||||
# Check that set_device was called
|
||||
assert any("sensor1.set_device" in expr for expr in added_expressions)
|
||||
|
||||
# For empty-name entities, Python passes 0 - C++ calculates hash at runtime
|
||||
assert any('set_name("", 0)' in expr for expr in added_expressions), (
|
||||
f"Expected set_name with hash 0, got {added_expressions}"
|
||||
)
|
||||
# For empty-name entities, Python stores hash 0 - C++ calculates hash at runtime
|
||||
assert config.get("_entity_name") == ""
|
||||
assert config.get("_entity_object_id_hash") == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -815,7 +802,6 @@ async def test_setup_entity_empty_name_with_mac_suffix(
|
||||
For empty-name entities, Python passes 0 and C++ calculates the hash
|
||||
at runtime from friendly_name (bug-for-bug compatibility).
|
||||
"""
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
# Set up CORE.config with name_add_mac_suffix enabled
|
||||
CORE.config = {"name_add_mac_suffix": True}
|
||||
@@ -831,10 +817,9 @@ async def test_setup_entity_empty_name_with_mac_suffix(
|
||||
|
||||
await _setup_entity_impl(var, config, "sensor")
|
||||
|
||||
# For empty-name entities, Python passes 0 - C++ calculates hash at runtime
|
||||
assert any('set_name("", 0)' in expr for expr in added_expressions), (
|
||||
f"Expected set_name with hash 0, got {added_expressions}"
|
||||
)
|
||||
# For empty-name entities, Python stores hash 0 - C++ calculates hash at runtime
|
||||
assert config.get("_entity_name") == ""
|
||||
assert config.get("_entity_object_id_hash") == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -847,7 +832,6 @@ async def test_setup_entity_empty_name_with_mac_suffix_no_friendly_name(
|
||||
at runtime. In this case C++ will hash the empty friendly_name
|
||||
(bug-for-bug compatibility).
|
||||
"""
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
# Set up CORE.config with name_add_mac_suffix enabled
|
||||
CORE.config = {"name_add_mac_suffix": True}
|
||||
@@ -863,10 +847,9 @@ async def test_setup_entity_empty_name_with_mac_suffix_no_friendly_name(
|
||||
|
||||
await _setup_entity_impl(var, config, "sensor")
|
||||
|
||||
# For empty-name entities, Python passes 0 - C++ calculates hash at runtime
|
||||
assert any('set_name("", 0)' in expr for expr in added_expressions), (
|
||||
f"Expected set_name with hash 0, got {added_expressions}"
|
||||
)
|
||||
# For empty-name entities, Python stores hash 0 - C++ calculates hash at runtime
|
||||
assert config.get("_entity_name") == ""
|
||||
assert config.get("_entity_object_id_hash") == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -878,7 +861,6 @@ async def test_setup_entity_empty_name_no_mac_suffix_no_friendly_name(
|
||||
For empty-name entities, Python passes 0 and C++ calculates the hash
|
||||
at runtime from the device name.
|
||||
"""
|
||||
added_expressions = setup_test_environment
|
||||
|
||||
# No MAC suffix (either not set or False)
|
||||
CORE.config = {}
|
||||
@@ -896,10 +878,9 @@ async def test_setup_entity_empty_name_no_mac_suffix_no_friendly_name(
|
||||
|
||||
await _setup_entity_impl(var, config, "sensor")
|
||||
|
||||
# For empty-name entities, Python passes 0 - C++ calculates hash at runtime
|
||||
assert any('set_name("", 0)' in expr for expr in added_expressions), (
|
||||
f"Expected set_name with hash 0, got {added_expressions}"
|
||||
)
|
||||
# For empty-name entities, Python stores hash 0 - C++ calculates hash at runtime
|
||||
assert config.get("_entity_name") == ""
|
||||
assert config.get("_entity_object_id_hash") == 0
|
||||
|
||||
|
||||
def test_register_string_overflow() -> None:
|
||||
@@ -976,7 +957,7 @@ async def test_setup_entity_direct_call(setup_test_environment: list[str]) -> No
|
||||
# Direct call mode: await setup_entity(var, config, "camera")
|
||||
await setup_entity(var, config, "camera")
|
||||
|
||||
# Should have called set_name
|
||||
# Should have emitted configure_entity_
|
||||
object_id = extract_object_id_from_expressions(added_expressions)
|
||||
assert object_id == "my_camera"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user