From dabf277942ea9b783305726dad7dfc081ec9dabd Mon Sep 17 00:00:00 2001 From: topsworld Date: Thu, 19 Dec 2024 13:30:26 +0800 Subject: [PATCH 1/3] test: check lang_integrity --- test/check_rule_format.py | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/test/check_rule_format.py b/test/check_rule_format.py index db2d8295..00ba86ac 100644 --- a/test/check_rule_format.py +++ b/test/check_rule_format.py @@ -4,6 +4,7 @@ from os import listdir, path from typing import Optional import pytest +import yaml SOURCE_DIR: str = path.dirname(path.abspath(__file__)) @@ -20,6 +21,18 @@ def load_json_file(file_path: str) -> Optional[dict]: return None +def load_yaml_file(file_path: str) -> Optional[dict]: + try: + with open(file_path, 'r', encoding='utf-8') as file: + return yaml.safe_load(file) + except FileNotFoundError: + print(file_path, 'is not found.') + return None + except yaml.YAMLError: + print(file_path, 'is not a valid YAML file.') + return None + + def dict_str_str(d: dict) -> bool: """restricted format: dict[str, str]""" if not isinstance(d, dict): @@ -86,6 +99,30 @@ def bool_trans(d: dict) -> bool: return True +def compare_dict_structure(dict1: dict, dict2: dict) -> bool: + if not isinstance(dict1, dict) or not isinstance(dict2, dict): + print('invalid type') + return False + if dict1.keys() != dict2.keys(): + print('inconsistent key values, ', dict1.keys(), dict2.keys()) + return False + for key in dict1: + if isinstance(dict1[key], dict) and isinstance(dict2[key], dict): + if not compare_dict_structure(dict1[key], dict2[key]): + print('inconsistent key values, dict, ', key) + return False + elif isinstance(dict1[key], list) and isinstance(dict2[key], list): + if not all( + isinstance(i, type(j)) + for i, j in zip(dict1[key], dict2[key])): + print('inconsistent key values, list, ', key) + return False + elif not isinstance(dict1[key], type(dict2[key])): + print('inconsistent key values, type, ', key) + return False + return True + + @pytest.mark.github def test_bool_trans(): data: dict = load_json_file( @@ -125,3 +162,62 @@ def test_miot_i18n(): data: dict = load_json_file(file_path) assert data assert nested_3_dict_str_str(data) + + +@pytest.mark.github +def test_translations(): + i18n_path: str = path.join( + SOURCE_DIR, '../custom_components/xiaomi_home/translations') + for file_name in listdir(i18n_path): + file_path: str = path.join(i18n_path, file_name) + data: dict = load_json_file(file_path) + assert data + assert dict_str_dict(data) + + +@pytest.mark.github +def test_miot_lang_integrity(): + # pylint: disable=import-outside-toplevel + from miot.const import INTEGRATION_LANGUAGES + integration_lang_list: list[str] = [ + f'{key}.json' for key in list(INTEGRATION_LANGUAGES.keys())] + translations_names: set[str] = set(listdir( + path.join( + SOURCE_DIR, '../custom_components/xiaomi_home/translations'))) + assert len(translations_names) == len(integration_lang_list) + assert translations_names == set(integration_lang_list) + i18n_names: set[str] = set(listdir( + path.join( + SOURCE_DIR, '../custom_components/xiaomi_home/miot/i18n'))) + assert len(i18n_names) == len(translations_names) + assert i18n_names == translations_names + # Check translation files structure + default_dict: dict = load_json_file( + path.join( + SOURCE_DIR, + '../custom_components/xiaomi_home/translations', + integration_lang_list[0])) + for name in list(integration_lang_list)[1:]: + compare_dict: dict = load_json_file( + path.join( + SOURCE_DIR, + '../custom_components/xiaomi_home/translations', + name)) + if not compare_dict_structure(default_dict, compare_dict): + print('compare_dict_structure failed /translations, ', name) + assert False + # Check i18n files structure + default_dict = load_json_file( + path.join( + SOURCE_DIR, + '../custom_components/xiaomi_home/miot/i18n', + integration_lang_list[0])) + for name in list(integration_lang_list)[1:]: + compare_dict: dict = load_json_file( + path.join( + SOURCE_DIR, + '../custom_components/xiaomi_home/miot/i18n', + name)) + if not compare_dict_structure(default_dict, compare_dict): + print('compare_dict_structure failed /miot/i18n, ', name) + assert False From b93d8631b8c079c194f04e4bb0a727b5a37f803d Mon Sep 17 00:00:00 2001 From: topsworld Date: Thu, 19 Dec 2024 13:31:17 +0800 Subject: [PATCH 2/3] fix: translations structure error --- .../xiaomi_home/miot/i18n/zh-Hant.json | 12 +++++------- custom_components/xiaomi_home/translations/ja.json | 4 +--- custom_components/xiaomi_home/translations/ru.json | 14 +++++++------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/custom_components/xiaomi_home/miot/i18n/zh-Hant.json b/custom_components/xiaomi_home/miot/i18n/zh-Hant.json index bf381a3f..e62b4f96 100644 --- a/custom_components/xiaomi_home/miot/i18n/zh-Hant.json +++ b/custom_components/xiaomi_home/miot/i18n/zh-Hant.json @@ -43,20 +43,18 @@ }, "error": { "common": { - "-1": "未知錯誤", "-10000": "未知錯誤", "-10001": "服務不可用", - "-10002": "無效參數", + "-10002": "參數無效", "-10003": "資源不足", "-10004": "內部錯誤", "-10005": "權限不足", "-10006": "執行超時", "-10007": "設備離線或者不存在", - "-10020": "無效的消息格式" - }, - "gw": {}, - "lan": {}, - "cloud": { + "-10020": "未授權(OAuth2)", + "-10030": "無效的token(HTTP)", + "-10040": "無效的消息格式", + "-10050": "無效的證書", "-704000000": "未知錯誤", "-704010000": "未授權(設備可能被刪除)", "-704014006": "沒找到設備描述", diff --git a/custom_components/xiaomi_home/translations/ja.json b/custom_components/xiaomi_home/translations/ja.json index 96d8029d..780378db 100644 --- a/custom_components/xiaomi_home/translations/ja.json +++ b/custom_components/xiaomi_home/translations/ja.json @@ -45,9 +45,7 @@ "get_cert_error": "ゲートウェイ証明書を取得できませんでした。", "no_family_selected": "家庭が選択されていません。", "no_devices": "選択された家庭にデバイスがありません。デバイスがある家庭を選択して続行してください。", - "no_central_device": "【中央ゲートウェイモード】Home Assistant が存在する LAN 内に使用可能な Xiaomi 中央ゲートウェイがある必要があります。選択された家庭がこの要件を満たしているかどうかを確認してください。", - "update_config_error": "設定情報の更新に失敗しました。", - "not_confirm": "変更項目が確認されていません。確認を選択してから送信してください。" + "no_central_device": "【中央ゲートウェイモード】Home Assistant が存在する LAN 内に使用可能な Xiaomi 中央ゲートウェイがある必要があります。選択された家庭がこの要件を満たしているかどうかを確認してください。" }, "abort": { "network_connect_error": "設定に失敗しました。ネットワーク接続に異常があります。デバイスのネットワーク設定を確認してください。", diff --git a/custom_components/xiaomi_home/translations/ru.json b/custom_components/xiaomi_home/translations/ru.json index 06c49ca7..778206de 100644 --- a/custom_components/xiaomi_home/translations/ru.json +++ b/custom_components/xiaomi_home/translations/ru.json @@ -45,13 +45,13 @@ "get_cert_error": "Не удалось получить сертификат центрального шлюза.", "no_family_selected": "Не выбрана домашняя сеть.", "no_devices": "В выбранной домашней сети нет устройств. Пожалуйста, выберите домашнюю сеть с устройствами и продолжайте.", - "no_central_device": "Для режима центрального шлюза Xiaomi необходимо наличие доступного центрального шлюза Xiaomi в локальной сети Home Assistant. Проверьте, соответствует ли выбранная домашняя сеть этому требованию.", - "abort": { - "network_connect_error": "Ошибка настройки. Сетевое подключение недоступно. Проверьте настройки сети устройства.", - "already_configured": "Этот пользователь уже настроен. Перейдите на страницу интеграции и нажмите кнопку «Настроить», чтобы изменить настройки.", - "invalid_auth_info": "Информация об авторизации истекла. Перейдите на страницу интеграции и нажмите кнопку «Настроить», чтобы переавторизоваться.", - "config_flow_error": "Ошибка настройки интеграции: {error}" - } + "no_central_device": "Для режима центрального шлюза Xiaomi необходимо наличие доступного центрального шлюза Xiaomi в локальной сети Home Assistant. Проверьте, соответствует ли выбранная домашняя сеть этому требованию." + }, + "abort": { + "network_connect_error": "Ошибка настройки. Сетевое подключение недоступно. Проверьте настройки сети устройства.", + "already_configured": "Этот пользователь уже настроен. Перейдите на страницу интеграции и нажмите кнопку «Настроить», чтобы изменить настройки.", + "invalid_auth_info": "Информация об авторизации истекла. Перейдите на страницу интеграции и нажмите кнопку «Настроить», чтобы переавторизоваться.", + "config_flow_error": "Ошибка настройки интеграции: {error}" } }, "options": { From 2d6387c30a86c3286a8b95306b551b701121f196 Mon Sep 17 00:00:00 2001 From: topsworld Date: Thu, 19 Dec 2024 13:53:53 +0800 Subject: [PATCH 3/3] test: check_rule_format.py use constant --- test/check_rule_format.py | 41 +++++++++++++-------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/test/check_rule_format.py b/test/check_rule_format.py index 00ba86ac..48d602ef 100644 --- a/test/check_rule_format.py +++ b/test/check_rule_format.py @@ -6,7 +6,9 @@ import pytest import yaml -SOURCE_DIR: str = path.dirname(path.abspath(__file__)) +SOURCE_PATH: str = path.dirname(path.abspath(__file__)) +TRANS_RELATIVE_PATH: str = '../custom_components/xiaomi_home/translations' +MIOT_I18N_RELATIVE_PATH: str = '../custom_components/xiaomi_home/miot/i18n' def load_json_file(file_path: str) -> Optional[dict]: @@ -127,7 +129,7 @@ def compare_dict_structure(dict1: dict, dict2: dict) -> bool: def test_bool_trans(): data: dict = load_json_file( path.join( - SOURCE_DIR, + SOURCE_PATH, '../custom_components/xiaomi_home/miot/specs/bool_trans.json')) assert data assert bool_trans(data) @@ -137,7 +139,7 @@ def test_bool_trans(): def test_spec_filter(): data: dict = load_json_file( path.join( - SOURCE_DIR, + SOURCE_PATH, '../custom_components/xiaomi_home/miot/specs/spec_filter.json')) assert data assert spec_filter(data) @@ -147,7 +149,7 @@ def test_spec_filter(): def test_multi_lang(): data: dict = load_json_file( path.join( - SOURCE_DIR, + SOURCE_PATH, '../custom_components/xiaomi_home/miot/specs/multi_lang.json')) assert data assert nested_3_dict_str_str(data) @@ -155,8 +157,7 @@ def test_multi_lang(): @pytest.mark.github def test_miot_i18n(): - i18n_path: str = path.join( - SOURCE_DIR, '../custom_components/xiaomi_home/miot/i18n') + i18n_path: str = path.join(SOURCE_PATH, MIOT_I18N_RELATIVE_PATH) for file_name in listdir(i18n_path): file_path: str = path.join(i18n_path, file_name) data: dict = load_json_file(file_path) @@ -166,8 +167,7 @@ def test_miot_i18n(): @pytest.mark.github def test_translations(): - i18n_path: str = path.join( - SOURCE_DIR, '../custom_components/xiaomi_home/translations') + i18n_path: str = path.join(SOURCE_PATH, TRANS_RELATIVE_PATH) for file_name in listdir(i18n_path): file_path: str = path.join(i18n_path, file_name) data: dict = load_json_file(file_path) @@ -182,42 +182,29 @@ def test_miot_lang_integrity(): integration_lang_list: list[str] = [ f'{key}.json' for key in list(INTEGRATION_LANGUAGES.keys())] translations_names: set[str] = set(listdir( - path.join( - SOURCE_DIR, '../custom_components/xiaomi_home/translations'))) + path.join(SOURCE_PATH, TRANS_RELATIVE_PATH))) assert len(translations_names) == len(integration_lang_list) assert translations_names == set(integration_lang_list) i18n_names: set[str] = set(listdir( - path.join( - SOURCE_DIR, '../custom_components/xiaomi_home/miot/i18n'))) + path.join(SOURCE_PATH, MIOT_I18N_RELATIVE_PATH))) assert len(i18n_names) == len(translations_names) assert i18n_names == translations_names # Check translation files structure default_dict: dict = load_json_file( - path.join( - SOURCE_DIR, - '../custom_components/xiaomi_home/translations', - integration_lang_list[0])) + path.join(SOURCE_PATH, TRANS_RELATIVE_PATH, integration_lang_list[0])) for name in list(integration_lang_list)[1:]: compare_dict: dict = load_json_file( - path.join( - SOURCE_DIR, - '../custom_components/xiaomi_home/translations', - name)) + path.join(SOURCE_PATH, TRANS_RELATIVE_PATH, name)) if not compare_dict_structure(default_dict, compare_dict): print('compare_dict_structure failed /translations, ', name) assert False # Check i18n files structure default_dict = load_json_file( path.join( - SOURCE_DIR, - '../custom_components/xiaomi_home/miot/i18n', - integration_lang_list[0])) + SOURCE_PATH, MIOT_I18N_RELATIVE_PATH, integration_lang_list[0])) for name in list(integration_lang_list)[1:]: compare_dict: dict = load_json_file( - path.join( - SOURCE_DIR, - '../custom_components/xiaomi_home/miot/i18n', - name)) + path.join(SOURCE_PATH, MIOT_I18N_RELATIVE_PATH, name)) if not compare_dict_structure(default_dict, compare_dict): print('compare_dict_structure failed /miot/i18n, ', name) assert False