mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
more cover
This commit is contained in:
@@ -4,6 +4,12 @@ esphome:
|
||||
# Enable MAC suffix - host MAC is 98:35:69:ab:f6:79, suffix is "abf679"
|
||||
# friendly_name becomes "Test Device abf679"
|
||||
name_add_mac_suffix: true
|
||||
# Sub-devices for testing empty-name entities on devices
|
||||
devices:
|
||||
- id: sub_device_1
|
||||
name: Sub Device One
|
||||
- id: sub_device_2
|
||||
name: Sub Device Two
|
||||
|
||||
host:
|
||||
|
||||
@@ -93,3 +99,27 @@ text_sensor:
|
||||
id: text_num_start
|
||||
lambda: return {"test"};
|
||||
update_interval: 60s
|
||||
|
||||
button:
|
||||
# Test 12: Named entity on sub-device -> object_id from entity name
|
||||
- platform: template
|
||||
name: "Device Button"
|
||||
id: button_on_device
|
||||
device_id: sub_device_1
|
||||
on_press: []
|
||||
|
||||
# Test 13: Empty name on sub-device -> object_id from device name
|
||||
# Device name "Sub Device One" -> object_id = "sub_device_one"
|
||||
- platform: template
|
||||
name: ""
|
||||
id: button_empty_on_device1
|
||||
device_id: sub_device_1
|
||||
on_press: []
|
||||
|
||||
# Test 14: Empty name on different sub-device
|
||||
# Device name "Sub Device Two" -> object_id = "sub_device_two"
|
||||
- platform: template
|
||||
name: ""
|
||||
id: button_empty_on_device2
|
||||
device_id: sub_device_2
|
||||
on_press: []
|
||||
|
||||
@@ -14,7 +14,9 @@ See: https://github.com/esphome/backlog/issues/76
|
||||
|
||||
Test cases covered:
|
||||
- Named entities with various characters (uppercase, special chars, hyphens, etc.)
|
||||
- Empty-name entities (has_own_name=false, uses device's friendly_name)
|
||||
- Empty-name entities on main device (uses device's friendly_name with MAC suffix)
|
||||
- Empty-name entities on sub-devices (uses sub-device's name)
|
||||
- Named entities on sub-devices (uses entity name, not device name)
|
||||
- MAC suffix handling (name_add_mac_suffix modifies friendly_name at runtime)
|
||||
- Both object_id string and hash (key) verification
|
||||
"""
|
||||
@@ -48,6 +50,15 @@ NAMED_ENTITIES = [
|
||||
("My Very Long Switch Name Here", "my_very_long_switch_name_here"),
|
||||
# text_sensor platform
|
||||
("123 Start", "123_start"),
|
||||
# button platform - named entity on sub-device (uses entity name, not device name)
|
||||
("Device Button", "device_button"),
|
||||
]
|
||||
|
||||
# Sub-device names and their expected object_ids for empty-name entities
|
||||
# Format: (device_name, expected_object_id)
|
||||
SUB_DEVICE_EMPTY_NAME_ENTITIES = [
|
||||
("Sub Device One", "sub_device_one"),
|
||||
("Sub Device Two", "sub_device_two"),
|
||||
]
|
||||
|
||||
|
||||
@@ -122,47 +133,74 @@ async def test_object_id_api_verification(
|
||||
f"Python hash {hash_from_name:#x}, API key {entity.key:#x}"
|
||||
)
|
||||
|
||||
# === Test 2: Verify empty-name entity (has_own_name=false) ===
|
||||
# When entity has no name, the name field is empty in the API message
|
||||
# and the entity uses device's friendly_name (with MAC suffix) for display
|
||||
assert "" in entity_map, (
|
||||
"Empty-name entity not found. "
|
||||
f"Available entity names: {list(entity_map.keys())}"
|
||||
)
|
||||
empty_name_entity = entity_map[""]
|
||||
# === Test 2: Verify empty-name entities ===
|
||||
# Empty-name entities have name="" in API, object_id comes from:
|
||||
# - Main device: friendly_name (with MAC suffix)
|
||||
# - Sub-device: device name
|
||||
|
||||
# object_id is computed from friendly_name (which includes MAC suffix)
|
||||
expected_object_id_empty = compute_expected_object_id(expected_friendly_name)
|
||||
assert empty_name_entity.object_id == expected_object_id_empty, (
|
||||
f"Empty-name entity: object_id mismatch. "
|
||||
f"API: '{empty_name_entity.object_id}', expected: '{expected_object_id_empty}'"
|
||||
# Get all empty-name entities
|
||||
empty_name_entities = [e for e in entities if e.name == ""]
|
||||
# We expect 3: 1 on main device, 2 on sub-devices
|
||||
assert len(empty_name_entities) == 3, (
|
||||
f"Expected 3 empty-name entities, got {len(empty_name_entities)}"
|
||||
)
|
||||
|
||||
# Hash is also computed from friendly_name with MAC suffix
|
||||
expected_hash_empty = fnv1_hash_object_id(expected_friendly_name)
|
||||
assert empty_name_entity.key == expected_hash_empty, (
|
||||
f"Empty-name entity: hash mismatch. "
|
||||
f"API key: {empty_name_entity.key:#x}, expected: {expected_hash_empty:#x}"
|
||||
)
|
||||
# Build device_id -> device_name map from device_info
|
||||
device_id_to_name = {d.device_id: d.name for d in device_info.devices}
|
||||
|
||||
# Verify each empty-name entity
|
||||
for entity in empty_name_entities:
|
||||
if entity.device_id == 0:
|
||||
# Main device - uses friendly_name with MAC suffix
|
||||
expected_name = expected_friendly_name
|
||||
else:
|
||||
# Sub-device - uses device name
|
||||
assert entity.device_id in device_id_to_name, (
|
||||
f"Entity device_id {entity.device_id} not found in devices"
|
||||
)
|
||||
expected_name = device_id_to_name[entity.device_id]
|
||||
|
||||
expected_object_id = compute_expected_object_id(expected_name)
|
||||
assert entity.object_id == expected_object_id, (
|
||||
f"Empty-name entity (device_id={entity.device_id}): object_id mismatch. "
|
||||
f"API: '{entity.object_id}', expected: '{expected_object_id}' "
|
||||
f"(from name '{expected_name}')"
|
||||
)
|
||||
|
||||
# Verify hash matches
|
||||
expected_hash = fnv1_hash_object_id(expected_name)
|
||||
assert entity.key == expected_hash, (
|
||||
f"Empty-name entity (device_id={entity.device_id}): hash mismatch. "
|
||||
f"API key: {entity.key:#x}, expected: {expected_hash:#x}"
|
||||
)
|
||||
|
||||
# === Test 3: Verify ALL entities can have object_id computed from API data ===
|
||||
# This is the key property for removing object_id from the API protocol
|
||||
for entity in entities:
|
||||
# Use entity name if present, otherwise device's friendly_name
|
||||
name_for_object_id = entity.name or device_info.friendly_name
|
||||
if entity.name:
|
||||
# Named entity - use entity name
|
||||
name_for_object_id = entity.name
|
||||
elif entity.device_id == 0:
|
||||
# Empty name on main device - use friendly_name
|
||||
name_for_object_id = device_info.friendly_name
|
||||
else:
|
||||
# Empty name on sub-device - use device name
|
||||
name_for_object_id = device_id_to_name[entity.device_id]
|
||||
|
||||
# Compute object_id from the appropriate name
|
||||
computed_object_id = compute_expected_object_id(name_for_object_id)
|
||||
|
||||
# Verify it matches what the API returned
|
||||
assert entity.object_id == computed_object_id, (
|
||||
f"Entity (name='{entity.name}'): object_id cannot be computed. "
|
||||
f"Entity (name='{entity.name}', device_id={entity.device_id}): "
|
||||
f"object_id cannot be computed. "
|
||||
f"API: '{entity.object_id}', Computed from '{name_for_object_id}': '{computed_object_id}'"
|
||||
)
|
||||
|
||||
# Verify hash can also be computed
|
||||
computed_hash = fnv1_hash_object_id(name_for_object_id)
|
||||
assert entity.key == computed_hash, (
|
||||
f"Entity (name='{entity.name}'): hash cannot be computed. "
|
||||
f"Entity (name='{entity.name}', device_id={entity.device_id}): "
|
||||
f"hash cannot be computed. "
|
||||
f"API key: {entity.key:#x}, Computed: {computed_hash:#x}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user