mirror of
https://github.com/esphome/esphome.git
synced 2026-09-14 16:48:40 +00:00
make it safer
This commit is contained in:
@@ -11,7 +11,7 @@ static const char *const TAG = "entity_base";
|
||||
// Entity Name
|
||||
const StringRef &EntityBase::get_name() const { return this->name_; }
|
||||
|
||||
void EntityBase::configure_entity(const char *name, uint32_t object_id_hash, uint32_t entity_strings_packed) {
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
@@ -52,9 +56,6 @@ class EntityBase {
|
||||
// Get the name of this Entity
|
||||
const StringRef &get_name() const;
|
||||
|
||||
/// 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);
|
||||
|
||||
// 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; }
|
||||
|
||||
@@ -201,6 +202,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);
|
||||
|
||||
@@ -34,7 +34,7 @@ _KEY_ICON_IDX = "_entity_icon_idx"
|
||||
_KEY_ENTITY_NAME = "_entity_name"
|
||||
_KEY_OBJECT_ID_HASH = "_entity_object_id_hash"
|
||||
|
||||
# Bit layout for entity_strings_packed in configure_entity() — must match C++ 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
|
||||
@@ -217,7 +217,7 @@ def setup_unit_of_measurement(config: ConfigType) -> None:
|
||||
|
||||
|
||||
def finalize_entity_strings(var: MockObj, config: ConfigType) -> None:
|
||||
"""Emit a single configure_entity() call with name, hash, and packed string 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.
|
||||
@@ -228,7 +228,7 @@ def finalize_entity_strings(var: MockObj, config: ConfigType) -> None:
|
||||
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)
|
||||
add(var.configure_entity(entity_name, object_id_hash, packed))
|
||||
add(var.configure_entity_(entity_name, object_id_hash, packed))
|
||||
|
||||
|
||||
def get_base_entity_object_id(
|
||||
@@ -330,7 +330,7 @@ async def _setup_entity_impl(var: MockObj, config: ConfigType, platform: str) ->
|
||||
device: MockObj = await get_variable(device_id_obj)
|
||||
add(var.set_device(device))
|
||||
|
||||
# Pre-compute entity name and object_id hash for configure_entity()
|
||||
# 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
|
||||
|
||||
@@ -29,7 +29,7 @@ def test_binary_sensor_sets_mandatory_fields(generate_main):
|
||||
)
|
||||
|
||||
# Then
|
||||
assert 'bs_1->configure_entity("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->configure_entity("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
|
||||
|
||||
|
||||
|
||||
@@ -11,4 +11,4 @@ def test_sensor_device_class_set(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/sensor/test_sensor.yaml")
|
||||
|
||||
# Then
|
||||
assert "s_1->configure_entity(" in main_cpp
|
||||
assert "s_1->configure_entity_(" in main_cpp
|
||||
|
||||
@@ -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->configure_entity("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):
|
||||
|
||||
@@ -25,9 +25,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->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
|
||||
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):
|
||||
@@ -54,5 +54,5 @@ def test_text_sensor_device_class_set(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/text_sensor/test_text_sensor.yaml")
|
||||
|
||||
# Then
|
||||
assert "ts_2->configure_entity(" in main_cpp
|
||||
assert "ts_3->configure_entity(" in main_cpp
|
||||
assert "ts_2->configure_entity_(" in main_cpp
|
||||
assert "ts_3->configure_entity_(" in main_cpp
|
||||
|
||||
@@ -31,10 +31,10 @@ from esphome.helpers import sanitize, snake_case
|
||||
|
||||
from .common import load_config_from_fixture
|
||||
|
||||
# Pre-compiled regex pattern for extracting names from configure_entity/set_name calls
|
||||
# Matches: .configure_entity("name", ...) or .set_name("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)\(["\']([^"\']*)["\']'
|
||||
r'\.(?:configure_entity_|set_name)\(["\']([^"\']*)["\']'
|
||||
)
|
||||
|
||||
FIXTURES_DIR = Path(__file__).parent.parent / "fixtures" / "core" / "entity_helpers"
|
||||
@@ -291,7 +291,7 @@ def extract_object_id_from_config(config: dict[str, Any]) -> str | None:
|
||||
|
||||
|
||||
def extract_object_id_from_expressions(expressions: list[str]) -> str | None:
|
||||
"""Extract the object ID from configure_entity() calls in generated expressions."""
|
||||
"""Extract the object ID from configure_entity_() calls in generated expressions."""
|
||||
for expr in expressions:
|
||||
if match := ENTITY_NAME_PATTERN.search(expr):
|
||||
name = match.group(1)
|
||||
@@ -954,7 +954,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 emitted configure_entity
|
||||
# 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