mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	fixes
This commit is contained in:
		
							
								
								
									
										140
									
								
								tests/unit_tests/test_get_base_entity_object_id.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								tests/unit_tests/test_get_base_entity_object_id.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| """Test get_base_entity_object_id function matches C++ behavior.""" | ||||
|  | ||||
| from esphome.core import CORE | ||||
| from esphome.entity import get_base_entity_object_id | ||||
| from esphome.helpers import sanitize, snake_case | ||||
|  | ||||
|  | ||||
| class TestGetBaseEntityObjectId: | ||||
|     """Test that get_base_entity_object_id matches C++ EntityBase::get_object_id behavior.""" | ||||
|  | ||||
|     def test_with_entity_name(self) -> None: | ||||
|         """Test when entity has its own name - should use entity name.""" | ||||
|         # Simple name | ||||
|         assert ( | ||||
|             get_base_entity_object_id("Temperature Sensor", None) | ||||
|             == "temperature_sensor" | ||||
|         ) | ||||
|         assert ( | ||||
|             get_base_entity_object_id("Temperature Sensor", "Device Name") | ||||
|             == "temperature_sensor" | ||||
|         ) | ||||
|  | ||||
|         # Name with special characters | ||||
|         assert ( | ||||
|             get_base_entity_object_id("Temp!@#$%^&*()Sensor", None) | ||||
|             == "temp__________sensor" | ||||
|         ) | ||||
|         assert get_base_entity_object_id("Temp-Sensor_123", None) == "temp-sensor_123" | ||||
|  | ||||
|         # Already snake_case | ||||
|         assert ( | ||||
|             get_base_entity_object_id("temperature_sensor", None) | ||||
|             == "temperature_sensor" | ||||
|         ) | ||||
|  | ||||
|         # Mixed case | ||||
|         assert ( | ||||
|             get_base_entity_object_id("TemperatureSensor", None) == "temperaturesensor" | ||||
|         ) | ||||
|         assert ( | ||||
|             get_base_entity_object_id("TEMPERATURE SENSOR", None) | ||||
|             == "temperature_sensor" | ||||
|         ) | ||||
|  | ||||
|     def test_empty_name_with_friendly_name(self) -> None: | ||||
|         """Test when entity has empty name - should use friendly name.""" | ||||
|         # C++ behavior: when has_own_name is false, uses App.get_friendly_name() | ||||
|         assert get_base_entity_object_id("", "Friendly Device") == "friendly_device" | ||||
|         assert ( | ||||
|             get_base_entity_object_id("", "Kitchen Controller") == "kitchen_controller" | ||||
|         ) | ||||
|         assert get_base_entity_object_id("", "Test-Device_123") == "test-device_123" | ||||
|  | ||||
|         # Special characters in friendly name | ||||
|         assert get_base_entity_object_id("", "Device!@#$%") == "device_____" | ||||
|  | ||||
|     def test_empty_name_no_friendly_name(self) -> None: | ||||
|         """Test when entity has empty name and no friendly name - should use device name.""" | ||||
|         # Save original values | ||||
|         original_name = getattr(CORE, "name", None) | ||||
|  | ||||
|         try: | ||||
|             # Test with CORE.name set | ||||
|             CORE.name = "device-name" | ||||
|             assert get_base_entity_object_id("", None) == "device-name" | ||||
|  | ||||
|             CORE.name = "Test Device" | ||||
|             assert get_base_entity_object_id("", None) == "test_device" | ||||
|  | ||||
|         finally: | ||||
|             # Restore original value | ||||
|             if original_name is not None: | ||||
|                 CORE.name = original_name | ||||
|  | ||||
|     def test_edge_cases(self) -> None: | ||||
|         """Test edge cases.""" | ||||
|         # Only spaces | ||||
|         assert get_base_entity_object_id("   ", None) == "___" | ||||
|  | ||||
|         # Unicode characters (should be replaced) | ||||
|         assert get_base_entity_object_id("Température", None) == "temp_rature" | ||||
|         assert get_base_entity_object_id("测试", None) == "__" | ||||
|  | ||||
|         # Empty string with empty friendly name (empty friendly name is treated as None) | ||||
|         # Falls back to CORE.name | ||||
|         original_name = getattr(CORE, "name", None) | ||||
|         try: | ||||
|             CORE.name = "device" | ||||
|             assert get_base_entity_object_id("", "") == "device" | ||||
|         finally: | ||||
|             if original_name is not None: | ||||
|                 CORE.name = original_name | ||||
|  | ||||
|         # Very long name (should work fine) | ||||
|         long_name = "a" * 100 + " " + "b" * 100 | ||||
|         expected = "a" * 100 + "_" + "b" * 100 | ||||
|         assert get_base_entity_object_id(long_name, None) == expected | ||||
|  | ||||
|     def test_matches_cpp_helpers(self) -> None: | ||||
|         """Test that the logic matches using snake_case and sanitize directly.""" | ||||
|         test_cases = [ | ||||
|             ("Temperature Sensor", "temperature_sensor"), | ||||
|             ("Living Room Light", "living_room_light"), | ||||
|             ("Test-Device_123", "test-device_123"), | ||||
|             ("Special!@#Chars", "special___chars"), | ||||
|             ("UPPERCASE NAME", "uppercase_name"), | ||||
|             ("lowercase name", "lowercase_name"), | ||||
|             ("Mixed Case Name", "mixed_case_name"), | ||||
|             ("   Spaces   ", "___spaces___"), | ||||
|         ] | ||||
|  | ||||
|         for name, expected in test_cases: | ||||
|             # For non-empty names, verify our function produces same result as direct snake_case + sanitize | ||||
|             assert get_base_entity_object_id(name, None) == sanitize(snake_case(name)) | ||||
|             assert get_base_entity_object_id(name, None) == expected | ||||
|  | ||||
|         # Empty name is handled specially - it doesn't just use sanitize(snake_case("")) | ||||
|         # Instead it falls back to friendly_name or CORE.name | ||||
|         assert sanitize(snake_case("")) == ""  # Direct conversion gives empty string | ||||
|         # But our function returns a fallback | ||||
|         original_name = getattr(CORE, "name", None) | ||||
|         try: | ||||
|             CORE.name = "device" | ||||
|             assert get_base_entity_object_id("", None) == "device"  # Uses device name | ||||
|         finally: | ||||
|             if original_name is not None: | ||||
|                 CORE.name = original_name | ||||
|  | ||||
|     def test_name_add_mac_suffix_behavior(self) -> None: | ||||
|         """Test behavior related to name_add_mac_suffix. | ||||
|  | ||||
|         In C++, when name_add_mac_suffix is enabled and entity has no name, | ||||
|         get_object_id() returns str_sanitize(str_snake_case(App.get_friendly_name())) | ||||
|         dynamically. Our function always returns the same result since we're | ||||
|         calculating the base for duplicate tracking. | ||||
|         """ | ||||
|         # The function should always return the same result regardless of | ||||
|         # name_add_mac_suffix setting, as we're calculating the base object_id | ||||
|         assert get_base_entity_object_id("", "Test Device") == "test_device" | ||||
|         assert get_base_entity_object_id("Entity Name", "Test Device") == "entity_name" | ||||
		Reference in New Issue
	
	Block a user