Преглед изворни кода

Add unit tests for checking translations.
- Options strings are the same as initial config for all translation files.
- All entity names from the device configs are covered by the English translations.

Fix some errors.

Breaking change: Minco "Sensor" selection renamed to "Temperature Selection" to be consistent with other device configs. Since this was only released in 0.13.1 a couple of hours ago so won't have wide use yet, a migration is not provided.

Jason Rumney пре 4 година
родитељ
комит
0fd5906ba5

+ 1 - 1
custom_components/tuya_local/devices/minco_mh1823d_thermostat.yaml

@@ -110,7 +110,7 @@ primary_entity:
       name: unknown_105
 secondary_entities:
   - entity: select
-    name: Sensor
+    name: Temperature Sensor
     category: config
     icon: "mdi:thermometer"
     dps:

+ 1 - 1
custom_components/tuya_local/manifest.json

@@ -2,7 +2,7 @@
     "domain": "tuya_local",
     "iot_class": "local_polling",
     "name": "Tuya Local",
-    "version": "0.13.1",
+    "version": "0.13.2",
     "documentation": "https://github.com/make-all/tuya-local",
     "issue_tracker": "https://github.com/make-all/tuya-local/issues",
     "dependencies": [],

+ 110 - 102
custom_components/tuya_local/translations/en.json

@@ -35,7 +35,8 @@
 		    "sensor": "Include a sensor entity",
 		    "switch": "Include a switch entity",
 		    "binary_sensor_continuous_heat": "Include continuous heat alarm as a binary_sensor entity",
-		    "binary_sensor_defrost": "Include defrost as a binary_sensor entity.",
+		    "binary_sensor_defrost": "Include defrost as a binary_sensor entity",
+		    "binary_sensor_error": "Include error as a binary_sensor entity.",
 		    "binary_sensor_high_temperature": "Include high temperature alarm as a binary_sensor entity",
 		    "binary_sensor_low_temperature": "Include low temperature alarm as a binary_sensor entity",
 		    "binary_sensor_tank": "Include tank as a binary_sensor entity",
@@ -49,8 +50,8 @@
 		    "light_uv_sterilization": "Include UV sterilization as a light entity",
 		    "lock_child_lock": "Include child lock as a lock entity",
 		    "number_calibration_offset": "Include calibration offset as a number entity",
-		    "number_calibration_offset_internal": "Include calibration offset for internal sensor as a number entity",
 		    "number_calibration_offset_external": "Include calibration offset for external sensor as a number entity",
+		    "number_calibration_offset_internal": "Include calibration offset for internal sensor as a number entity",
 		    "number_calibration_swing": "Include calibration swing as a number entity",
 		    "number_continuous_heat_hours": "Include Continuous Heating Time as a number entity",
 		    "number_high_temperature_limit": "Include High Temperature Limit as a number entity",
@@ -60,26 +61,29 @@
 		    "number_timer": "Include timer as a number entity",
 		    "number_timer_1": "Include timer 1 as a number entity",
 		    "number_timer_2": "Include timer 2 as a number entity",
-		    "select_initial_state": "Include initial state as a select entity.",
-		    "select_installation": "Include installation as a select entity.",
+		    "select_configuration": "Include configuration as a select entity",
+		    "select_initial_state": "Include initial state as a select entity",
+		    "select_installation": "Include installation as a select entity",
 		    "select_schedule": "Include schedule as a select entity",
 		    "select_timer": "Include timer as a select entity",
 		    "select_temperature_sensor": "Include temperature sensor config as a select entity",
 		    "select_temperature_unit": "Include temerature unit as a select entity",
+		    "sensor_active_filter_life": "Include active filter life as a sensor entity",
 		    "sensor_air_quality": "Include air quality as a sensor entity",
-		    "sensor_prefilter_life": "Include prefilter life as a sensor entity",
 		    "sensor_charcoal_filter_life": "Include charcoal filter life as a sensor entity",
-		    "sensor_active_filter_life": "Include active filter life as a sensor entity",
-		    "sensor_hepa_filter_life": "Include HEPA filter life as a sensor entity",
+		    "sensor_current": "Include current as a sensor entity",
 		    "sensor_current_humidity": "Include current humidity as a sensor entity",
 		    "sensor_current_temperature": "Include current temperature as a sensor entity",
+		    "sensor_energy": "Include energy as a sensor entity",
 		    "sensor_external_temperature": "Include external temperature as a sensor entity",
+		    "sensor_floor_temperature": "Include floor temperature as a sensor entity",
+		    "sensor_hepa_filter_life": "Include HEPA filter life as a sensor entity",
+		    "sensor_open": "Include open as a sensor entity",
+		    "sensor_power": "Include power as a sensor entity",
 		    "sensor_power_level": "Include power level as a sensor entity",
+		    "sensor_prefilter_life": "Include prefilter life as a sensor entity",
 		    "sensor_timer": "Include time remaining as a sensor entity",
-		    "sensor_floor_temperature": "Include floor temperature as a sensor entity",
-		    "sensor_current": "Include current as a sensor entity",
 		    "sensor_voltage": "Include voltage as a sensor entity",
-		    "sensor_open": "Include open as a sensor entity",
 		    "switch_adaptive": "Include adaptive as a switch entity",
 		    "switch_air_clean": "Include air clean as a switch entity",
 		    "switch_anti_frost": "Include anti-frost as a switch entity",
@@ -92,100 +96,104 @@
 		    "switch_sound": "Include sound mute as a switch entity",
 		    "switch_uv_sterilization": "Include UV sterilization as a switch"
 		}
+	    }
+	},
+	"abort": {
+	    "already_configured": "A device with that ID has already been added.",
+	    "not_supported": "Sorry, there is no support for this device."
+	},
+	"error": {
+	    "connection": "Unable to connect to your device with those details. It could be an intermittent issue, or they may be incorrect."
 	}
     },
-    "abort": {
-	"already_configured": "A device with that ID has already been added.",
-	"not_supported": "Sorry, there is no support for this device."
-    },
-    "error": {
-	"connection": "Unable to connect to your device with those details. It could be an intermittent issue, or they may be incorrect."
-    }
-},
-"options": {
-    "step": {
-	"user": {
-            "title": "Configure your Tuya Local device",
-            "description": "[Follow these instructions to find your local key.](https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md)",
-            "data": {
-		"host": "IP address or hostname",
-		"local_key": "Local key",
-		"binary_sensor": "Include a binary sensor entity",
-		"climate": "Include a climate entity",
-		"cover": "Include a cover entity",
-		"fan": "Include a fan entity",
-		"humidifier": "Include a humidifier entity",
-		"light": "Include a light entity",
-		"lock": "Include a lock entity",
-		"number": "Include a number entity",
-		"select": "Include a select entity",
-		"sensor": "Include a sensor entity",
-		"switch": "Include a switch entity",
-		"binary_sensor_continuous_heat": "Include continuous heat alarm as a binary_sensor entity",
-		"binary_sensor_defrost": "Include defrost as a binary_sensor entity.",
-		"binary_sensor_high_temperature": "Include high temperature alarm as a binary_sensor entity",
-		"binary_sensor_low_temperature": "Include low temperature alarm as a binary_sensor entity",
-		"binary_sensor_tank": "Include tank as a binary_sensor entity.",
-		"binary_sensor_water_flow": "Include water flow warning as a binary_sensor entity",
-		"climate_dehumidifier_as_climate": "Include a climate entity for the dehumidifier (deprecated, recommend using humidifier and fan instead)",
-		"fan_intensity": "Include intensity as a fan entity",
-		"light_aq_indicator": "Include AQ indicator as a light entity",
-		"light_backlight": "Include backlight as a light entity",
-		"light_display": "Include display as a light entity",
-		"light_flame": "Include flame as a light entity",
-		"light_uv_sterilization": "Include UV sterilization as a light entity",
-		"lock_child_lock": "Include child lock as a lock entity",
-		"number_calibration_offset": "Include calibration offset as a number entity",
-		"number_calibration_offset_internal": "Include calibration offset for internal sensor as a number entity",
-		"number_calibration_offset_external": "Include calibration offset for external sensor as a number entity",
-		"number_calibration_swing": "Include calibration swing as a number entity",
-		"number_continuous_heat_hours": "Include Continuous Heating Time as a number entity",
-		"number_high_temperature_limit": "Include High Temperature Limit as a number entity",
-		"number_low_temperature_limit": "Include Low Temperature Limit as a number entity",
-		"number_floor_temperature_limit": "Include Floor Temperature Limit as a number entity",
-		"number_power_rating": "Include Power Rating as a number entity",
-		"number_timer": "Include timer as a number entity",
-		"number_timer_1": "Include timer 1 as a number entity",
-		"number_timer_2": "Include timer 2 as a number entity",
-		"select_initial_state": "Include initial state as a select entity.",
-		"select_installation": "Include installation as a select entity.",
-		"select_schedule": "Include schedule as a select entity",
-		"select_timer": "Include timer as a select entity",
-		"select_temperature_sensor": "Include temperature sensor config as a select entity",
-		"select_temperature_unit": "Include temerature unit as a select entity",
-		"sensor_air_quality": "Include air quality as a sensor entity",
-		"sensor_prefilter_life": "Include prefilter life as a sensor entity",
-		"sensor_charcoal_filter_life": "Include charcoal filter life as a sensor entity",
-		"sensor_active_filter_life": "Include active filter life as a sensor entity",
-		"sensor_hepa_filter_life": "Include HEPA filter life as a sensor entity",
-		"sensor_current_humidity": "Include current humidity as a sensor entity",
-		"sensor_current_temperature": "Include current temperature as a sensor entity",
-		"sensor_external_temperature": "Include external temperature as a sensor entity",
-		"sensor_power_level": "Include power level as a sensor entity",
-		"sensor_timer": "Include time remaining as a sensor entity",
-		"sensor_floor_temperature": "Include floor temperature as a sensor entity",
-		"sensor_current": "Include current as a sensor entity",
-		"sensor_voltage": "Include voltage as a sensor entity",
-		"sensor_open": "Include open as a sensor entity",
-		"switch_adaptive": "Include adaptive as a switch entity",
-		"switch_air_clean": "Include air clean as a switch entity",
-		"switch_anti_frost": "Include anti-frost as a switch entity",
-		"switch_ionizer": "Include ionizer as a switch entity",
-		"switch_master": "Include master switch as a switch entity",
-		"switch_open_window_detector": "Include open window detect as a switch entity",
-		"switch_outlet_1": "Include outlet 1 as a switch entity",
-		"switch_outlet_2": "Include outlet 2 as a switch entity",
-		"switch_sleep": "Include sleep mode as a switch entity",
-		"switch_sound": "Include sound mute as a switch entity",
-		"switch_uv_sterilization": "Include UV sterilization as a switch"
-            }
+    "options": {
+	"step": {
+	    "user": {
+		"title": "Configure your Tuya Local device",
+		"description": "[Follow these instructions to find your local key.](https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md)",
+		"data": {
+		    "host": "IP address or hostname",
+		    "local_key": "Local key",
+		    "binary_sensor": "Include a binary sensor entity",
+		    "climate": "Include a climate entity",
+		    "cover": "Include a cover entity",
+		    "fan": "Include a fan entity",
+		    "humidifier": "Include a humidifier entity",
+		    "light": "Include a light entity",
+		    "lock": "Include a lock entity",
+		    "number": "Include a number entity",
+		    "select": "Include a select entity",
+		    "sensor": "Include a sensor entity",
+		    "switch": "Include a switch entity",
+		    "binary_sensor_continuous_heat": "Include continuous heat alarm as a binary_sensor entity",
+		    "binary_sensor_defrost": "Include defrost as a binary_sensor entity",
+		    "binary_sensor_error": "Include error as a binary_sensor entity.",
+		    "binary_sensor_high_temperature": "Include high temperature alarm as a binary_sensor entity",
+		    "binary_sensor_low_temperature": "Include low temperature alarm as a binary_sensor entity",
+		    "binary_sensor_tank": "Include tank as a binary_sensor entity",
+		    "binary_sensor_water_flow": "Include water flow warning as a binary_sensor entity",
+		    "climate_dehumidifier_as_climate": "Include a climate entity for the dehumidifier (deprecated, recommend using humidifier and fan instead)",
+		    "fan_intensity": "Include intensity as a fan entity",
+		    "light_aq_indicator": "Include AQ indicator as a light entity",
+		    "light_backlight": "Include backlight as a light entity",
+		    "light_display": "Include display as a light entity",
+		    "light_flame": "Include flame as a light entity",
+		    "light_uv_sterilization": "Include UV sterilization as a light entity",
+		    "lock_child_lock": "Include child lock as a lock entity",
+		    "number_calibration_offset": "Include calibration offset as a number entity",
+		    "number_calibration_offset_external": "Include calibration offset for external sensor as a number entity",
+		    "number_calibration_offset_internal": "Include calibration offset for internal sensor as a number entity",
+		    "number_calibration_swing": "Include calibration swing as a number entity",
+		    "number_continuous_heat_hours": "Include Continuous Heating Time as a number entity",
+		    "number_high_temperature_limit": "Include High Temperature Limit as a number entity",
+		    "number_low_temperature_limit": "Include Low Temperature Limit as a number entity",
+		    "number_floor_temperature_limit": "Include Floor Temperature Limit as a number entity",
+		    "number_power_rating": "Include Power Rating as a number entity",
+		    "number_timer": "Include timer as a number entity",
+		    "number_timer_1": "Include timer 1 as a number entity",
+		    "number_timer_2": "Include timer 2 as a number entity",
+		    "select_configuration": "Include configuration as a select entity",
+		    "select_initial_state": "Include initial state as a select entity",
+		    "select_installation": "Include installation as a select entity",
+		    "select_schedule": "Include schedule as a select entity",
+		    "select_timer": "Include timer as a select entity",
+		    "select_temperature_sensor": "Include temperature sensor config as a select entity",
+		    "select_temperature_unit": "Include temerature unit as a select entity",
+		    "sensor_active_filter_life": "Include active filter life as a sensor entity",
+		    "sensor_air_quality": "Include air quality as a sensor entity",
+		    "sensor_charcoal_filter_life": "Include charcoal filter life as a sensor entity",
+		    "sensor_current": "Include current as a sensor entity",
+		    "sensor_current_humidity": "Include current humidity as a sensor entity",
+		    "sensor_current_temperature": "Include current temperature as a sensor entity",
+		    "sensor_energy": "Include energy as a sensor entity",
+		    "sensor_external_temperature": "Include external temperature as a sensor entity",
+		    "sensor_floor_temperature": "Include floor temperature as a sensor entity",
+		    "sensor_hepa_filter_life": "Include HEPA filter life as a sensor entity",
+		    "sensor_open": "Include open as a sensor entity",
+		    "sensor_power": "Include power as a sensor entity",
+		    "sensor_power_level": "Include power level as a sensor entity",
+		    "sensor_prefilter_life": "Include prefilter life as a sensor entity",
+		    "sensor_timer": "Include time remaining as a sensor entity",
+		    "sensor_voltage": "Include voltage as a sensor entity",
+		    "switch_adaptive": "Include adaptive as a switch entity",
+		    "switch_air_clean": "Include air clean as a switch entity",
+		    "switch_anti_frost": "Include anti-frost as a switch entity",
+		    "switch_ionizer": "Include ionizer as a switch entity",
+		    "switch_master": "Include master switch as a switch entity",
+		    "switch_open_window_detector": "Include open window detect as a switch entity",
+		    "switch_outlet_1": "Include outlet 1 as a switch entity",
+		    "switch_outlet_2": "Include outlet 2 as a switch entity",
+		    "switch_sleep": "Include sleep mode as a switch entity",
+		    "switch_sound": "Include sound mute as a switch entity",
+		    "switch_uv_sterilization": "Include UV sterilization as a switch"
+		}
+	    }
+	},
+	"error": {
+	    "connection": "Unable to connect to your device with those details. It could be an intermittent issue, or they may be incorrect."
+	},
+	"abort": {
+	    "not_supported": "Sorry, there is no support for this device."
 	}
-    },
-    "error": {
-	"connection": "Unable to connect to your device with those details. It could be an intermittent issue, or they may be incorrect."
-    },
-    "abort": {
-	"not_supported": "Sorry, there is no support for this device."
     }
-  }
 }

+ 75 - 0
tests/test_translations.py

@@ -0,0 +1,75 @@
+"""
+Tests for translation files.
+"""
+from fnmatch import fnmatch
+from os import walk
+from os.path import join, dirname
+
+import pytest
+from unittest import TestCase
+
+from homeassistant.util.json import load_json
+
+import custom_components.tuya_local as root
+from custom_components.tuya_local.helpers.device_config import (
+    available_configs,
+    TuyaDeviceConfig,
+)
+
+
+def get_translations():
+    translations = join(dirname(root.__file__), "translations")
+    for (path, dirs, files) in walk(translations):
+        for file in files:
+            if fnmatch(file, "*.json"):
+                yield load_json(join(path, file))
+
+
+english = None
+
+
+def get_english():
+    global english
+    if english is None:
+        translations = join(dirname(root.__file__), "translations", "en.json")
+        json = load_json(translations)
+        english = json["config"]["step"]["choose_entities"]["data"]
+
+    return english
+
+
+def get_devices():
+    for device in available_configs():
+        yield TuyaDeviceConfig(device)
+
+
+@pytest.mark.parametrize("translations", get_translations())
+def test_config_and_options_match(translations):
+
+    config = translations["config"]["step"]["choose_entities"]["data"]
+    options = translations["options"]["step"]["user"]["data"]
+
+    # remove expected differences
+    config.pop("name", None)
+    options.pop("host", None)
+    options.pop("local_key", None)
+
+    test = TestCase()
+    test.maxDiff = None
+    test.assertDictEqual(config, options)
+
+
+def subtest_entity_covered(entity):
+    strings = get_english()
+    TestCase().assertIn(
+        entity.config_id, strings, f"{entity.config_id} is missing a translation"
+    )
+
+
+@pytest.mark.parametrize("device", get_devices())
+def test_device_covered(device):
+    entity = device.primary_entity
+    subtest_entity_covered(entity)
+
+    for entity in device.secondary_entities():
+        subtest_entity_covered(entity)