feat: update test case logic

This commit is contained in:
topsworld 2025-01-17 14:36:48 +08:00
parent a79fe144ab
commit ee1a910205
6 changed files with 229 additions and 244 deletions

View File

@ -977,8 +977,8 @@ class _SpecBoolTranslation:
DEFAULT_INTEGRATION_LANGUAGE, None))
if data_default:
self._data_default = [
{'value': True, 'description': data_default[True]},
{'value': False, 'description': data_default[False]}
{'value': True, 'description': data_default['true']},
{'value': False, 'description': data_default['false']}
]
for urn, key in data['data'].items():
@ -991,8 +991,8 @@ class _SpecBoolTranslation:
DEFAULT_INTEGRATION_LANGUAGE, None))
if trans_data:
self._data[urn] = [
{'value': True, 'description': trans_data[True]},
{'value': False, 'description': trans_data[False]}
{'value': True, 'description': trans_data['true']},
{'value': False, 'description': trans_data['false']}
]
async def deinit_async(self) -> None:

View File

@ -65,13 +65,13 @@ from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ed25519
from custom_components.xiaomi_home.miot.common import MIoTHttp
# pylint: disable=relative-beyond-top-level
from .const import (
MANUFACTURER_EFFECTIVE_TIME,
MIHOME_CA_CERT_STR,
MIHOME_CA_CERT_SHA256)
from .common import MIoTHttp
from .miot_error import MIoTCertError, MIoTError, MIoTStorageError
_LOGGER = logging.getLogger(__name__)
@ -217,7 +217,8 @@ class MIoTStorage:
w_bytes = json.dumps(data).encode('utf-8')
else:
_LOGGER.error(
'save error, unsupported data type, %s', type(data).__name__)
'save error, unsupported data type, %s',
type(data).__name__)
return False
with open(full_path, 'wb') as w_file:
w_file.write(w_bytes)

View File

@ -59,188 +59,188 @@ data:
urn:miot-spec-v2:property:wifi-ssid-hidden:000000E3: yes_no
urn:miot-spec-v2:property:wind-reverse:00000117: yes_no
translate:
default:
de:
true: Wahr
false: Falsch
en:
true: True
false: False
es:
true: Verdadero
false: Falso
fr:
true: Vrai
false: Faux
it:
true: Vero
false: Falso
ja:
true:
false:
nl:
true: True
false: False
pt:
true: True
false: False
pt-BR:
true: True
false: False
ru:
true: Истина
false: Ложь
zh-Hans:
true:
false:
zh-Hant:
true:
false:
open_close:
de:
true: Öffnen
false: Schließen
en:
true: Open
false: Close
es:
true: Abierto
false: Cerrado
fr:
true: Ouvert
false: Fermer
it:
true: Aperto
false: Chiuso
ja:
true: 開く
false: 閉じる
nl:
true: Open
false: Dicht
pt:
true: Aberto
false: Fechado
pt-BR:
true: Aberto
false: Fechado
ru:
true: Открыть
false: Закрыть
zh-Hans:
true: 开启
false: 关闭
zh-Hant:
true: 開啟
false: 關閉
yes_no:
de:
true: Ja
false: Nein
en:
true: Yes
false: No
es:
true:
false: No
fr:
true: Oui
false: Non
it:
true: Si
false: No
ja:
true: はい
false: いいえ
nl:
true: Ja
false: Nee
pt:
true: Sim
false: Não
pt-BR:
true: Sim
false: Não
ru:
true: Да
false: Нет
zh-Hans:
true:
false:
zh-Hant:
true:
false:
motion_state:
de:
true: Bewegung erkannt
false: Keine Bewegung erkannt
en:
true: Motion Detected
false: No Motion Detected
es:
true: Movimiento detectado
false: No se detecta movimiento
fr:
true: Mouvement détecté
false: Aucun mouvement détecté
it:
true: Movimento Rilevato,
false: Nessun Movimento Rilevato
ja:
true: 動きを検知
false: 動きが検出されません
nl:
true: Contact
false: Geen contact
pt:
true: Contato
false: Sem contato
pt-BR:
true: Contato
false: Sem contato
ru:
true: Обнаружено движение
false: Движение не обнаружено
zh-Hans:
true: 有人
false: 无人
zh-Hant:
true: 有人
false: 無人
contact_state:
de:
true: Kontakt
false: Kein Kontakt
'false': Kein Kontakt
'true': Kontakt
en:
true: Contact
false: No Contact
'false': No Contact
'true': Contact
es:
true: Contacto
false: Sin contacto
'false': Sin contacto
'true': Contacto
fr:
true: Contact
false: Pas de contact
'false': Pas de contact
'true': Contact
it:
true: Contatto
false: Nessun contatto
'false': Nessun contatto
'true': Contatto
ja:
true: 接触
false: 接触
'false': 非接触
'true': 接触
nl:
true: Contact
false: Geen contact
'false': Geen contact
'true': Contact
pt:
true: Contato
false: Sem contato
'false': Sem contato
'true': Contato
pt-BR:
true: Contato
false: Sem contato
'false': Sem contato
'true': Contato
ru:
true: Контакт
false: Нет контакта
'false': Нет контакта
'true': Контакт
zh-Hans:
true: 接触
false: 分离
'false': 分离
'true': 接触
zh-Hant:
true: 接觸
false: 分離
'false': 分離
'true': 接觸
default:
de:
'false': Falsch
'true': Wahr
en:
'false': 'False'
'true': 'True'
es:
'false': Falso
'true': Verdadero
fr:
'false': Faux
'true': Vrai
it:
'false': Falso
'true': Vero
ja:
'false':
'true':
nl:
'false': 'False'
'true': 'True'
pt:
'false': 'False'
'true': 'True'
pt-BR:
'false': 'False'
'true': 'True'
ru:
'false': Ложь
'true': Истина
zh-Hans:
'false':
'true':
zh-Hant:
'false':
'true':
motion_state:
de:
'false': Keine Bewegung erkannt
'true': Bewegung erkannt
en:
'false': No Motion Detected
'true': Motion Detected
es:
'false': No se detecta movimiento
'true': Movimiento detectado
fr:
'false': Aucun mouvement détecté
'true': Mouvement détecté
it:
'false': Nessun Movimento Rilevato
'true': Movimento Rilevato
ja:
'false': 動きが検出されません
'true': 動きを検知
nl:
'false': Geen contact
'true': Contact
pt:
'false': Sem contato
'true': Contato
pt-BR:
'false': Sem contato
'true': Contato
ru:
'false': Движение не обнаружено
'true': Обнаружено движение
zh-Hans:
'false': 无人
'true': 有人
zh-Hant:
'false': 無人
'true': 有人
open_close:
de:
'false': Schließen
'true': Öffnen
en:
'false': Close
'true': Open
es:
'false': Cerrado
'true': Abierto
fr:
'false': Fermer
'true': Ouvert
it:
'false': Chiuso
'true': Aperto
ja:
'false': 閉じる
'true': 開く
nl:
'false': Dicht
'true': Open
pt:
'false': Fechado
'true': Aberto
pt-BR:
'false': Fechado
'true': Aberto
ru:
'false': Закрыть
'true': Открыть
zh-Hans:
'false': 关闭
'true': 开启
zh-Hant:
'false': 關閉
'true': 開啟
yes_no:
de:
'false': Nein
'true': Ja
en:
'false': 'No'
'true': 'Yes'
es:
'false': 'No'
'true':
fr:
'false': Non
'true': Oui
it:
'false': 'No'
'true': Si
ja:
'false': いいえ
'true': はい
nl:
'false': Nee
'true': Ja
pt:
'false': Não
'true': Sim
pt-BR:
'false': Não
'true': Sim
ru:
'false': Нет
'true': Да
zh-Hans:
'false':
'true':
zh-Hant:
'false':
'true':

View File

@ -1,43 +1,43 @@
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ma4:
properties:
- "9.*"
- "13.*"
- "15.*"
- 9.*
- 13.*
- 15.*
services:
- "10"
- '10'
urn:miot-spec-v2:device:curtain:0000A00C:lumi-hmcn01:
properties:
- "5.1"
- '5.1'
services:
- "4"
- "7"
- "8"
- '4'
- '7'
- '8'
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:
events:
- "2.1"
- '2.1'
urn:miot-spec-v2:device:health-pot:0000A051:chunmi-a1:
services:
- "5"
- '5'
urn:miot-spec-v2:device:light:0000A001:philips-strip3:
properties:
- "2.2"
- '2.2'
services:
- "1"
- "3"
- '1'
- '3'
urn:miot-spec-v2:device:light:0000A001:yeelink-color2:
properties:
- "3.*"
- "2.5"
- 3.*
- '2.5'
urn:miot-spec-v2:device:light:0000A001:yeelink-dnlight2:
services:
- "3"
- '3'
urn:miot-spec-v2:device:light:0000A001:yeelink-mbulb3:
services:
- "3"
- '3'
urn:miot-spec-v2:device:motion-sensor:0000A014:xiaomi-pir1:
services:
- "1"
- "5"
- '1'
- '5'
urn:miot-spec-v2:device:router:0000A036:xiaomi-rd03:
services:
- "*"
- '*'

View File

@ -53,7 +53,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.components.sensor import SensorEntity, SensorDeviceClass
from homeassistant.components.sensor import DEVICE_CLASS_UNITS, SensorStateClass
from homeassistant.components.sensor import DEVICE_CLASS_UNITS
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
from .miot.miot_spec import MIoTSpecProperty

View File

@ -16,13 +16,10 @@ MIOT_I18N_RELATIVE_PATH: str = path.join(
ROOT_PATH, '../custom_components/xiaomi_home/miot/i18n')
SPEC_BOOL_TRANS_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/bool_trans.json')
SPEC_MULTI_LANG_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/multi_lang.json')
'../custom_components/xiaomi_home/miot/specs/bool_trans.yaml')
SPEC_FILTER_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/spec_filter.json')
'../custom_components/xiaomi_home/miot/specs/spec_filter.yaml')
def load_json_file(file_path: str) -> Optional[dict]:
@ -54,6 +51,12 @@ def load_yaml_file(file_path: str) -> Optional[dict]:
return None
def save_yaml_file(file_path: str, data: dict) -> None:
with open(file_path, 'w', encoding='utf-8') as file:
yaml.safe_dump(
data, file, default_flow_style=False, allow_unicode=True, indent=2)
def dict_str_str(d: dict) -> bool:
"""restricted format: dict[str, str]"""
if not isinstance(d, dict):
@ -161,25 +164,17 @@ def compare_dict_structure(dict1: dict, dict2: dict) -> bool:
def sort_bool_trans(file_path: str):
trans_data: dict = load_json_file(file_path=file_path)
trans_data = load_yaml_file(file_path=file_path)
assert isinstance(trans_data, dict), f'{file_path} format error'
trans_data['data'] = dict(sorted(trans_data['data'].items()))
for key, trans in trans_data['translate'].items():
trans_data['translate'][key] = dict(sorted(trans.items()))
return trans_data
def sort_multi_lang(file_path: str):
multi_lang: dict = load_json_file(file_path=file_path)
multi_lang = dict(sorted(multi_lang.items()))
for urn, trans in multi_lang.items():
multi_lang[urn] = dict(sorted(trans.items()))
for lang, spec in multi_lang[urn].items():
multi_lang[urn][lang] = dict(sorted(spec.items()))
return multi_lang
def sort_spec_filter(file_path: str):
filter_data: dict = load_json_file(file_path=file_path)
filter_data = load_yaml_file(file_path=file_path)
assert isinstance(filter_data, dict), f'{file_path} format error'
filter_data = dict(sorted(filter_data.items()))
for urn, spec in filter_data.items():
filter_data[urn] = dict(sorted(spec.items()))
@ -188,30 +183,26 @@ def sort_spec_filter(file_path: str):
@pytest.mark.github
def test_bool_trans():
data: dict = load_json_file(SPEC_BOOL_TRANS_FILE)
data = load_yaml_file(SPEC_BOOL_TRANS_FILE)
assert isinstance(data, dict)
assert data, f'load {SPEC_BOOL_TRANS_FILE} failed'
assert bool_trans(data), f'{SPEC_BOOL_TRANS_FILE} format error'
@pytest.mark.github
def test_spec_filter():
data: dict = load_json_file(SPEC_FILTER_FILE)
data = load_yaml_file(SPEC_FILTER_FILE)
assert isinstance(data, dict)
assert data, f'load {SPEC_FILTER_FILE} failed'
assert spec_filter(data), f'{SPEC_FILTER_FILE} format error'
@pytest.mark.github
def test_multi_lang():
data: dict = load_json_file(SPEC_MULTI_LANG_FILE)
assert data, f'load {SPEC_MULTI_LANG_FILE} failed'
assert nested_3_dict_str_str(data), f'{SPEC_MULTI_LANG_FILE} format error'
@pytest.mark.github
def test_miot_i18n():
for file_name in listdir(MIOT_I18N_RELATIVE_PATH):
file_path: str = path.join(MIOT_I18N_RELATIVE_PATH, file_name)
data: dict = load_json_file(file_path)
data = load_json_file(file_path)
assert isinstance(data, dict)
assert data, f'load {file_path} failed'
assert nested_3_dict_str_str(data), f'{file_path} format error'
@ -220,7 +211,8 @@ def test_miot_i18n():
def test_translations():
for file_name in listdir(TRANS_RELATIVE_PATH):
file_path: str = path.join(TRANS_RELATIVE_PATH, file_name)
data: dict = load_json_file(file_path)
data = load_json_file(file_path)
assert isinstance(data, dict)
assert data, f'load {file_path} failed'
assert dict_str_dict(data), f'{file_path} format error'
@ -237,15 +229,16 @@ def test_miot_lang_integrity():
i18n_names: set[str] = set(listdir(MIOT_I18N_RELATIVE_PATH))
assert len(i18n_names) == len(translations_names)
assert i18n_names == translations_names
bool_trans_data: set[str] = load_json_file(SPEC_BOOL_TRANS_FILE)
bool_trans_data = load_yaml_file(SPEC_BOOL_TRANS_FILE)
assert isinstance(bool_trans_data, dict)
bool_trans_names: set[str] = set(
bool_trans_data['translate']['default'].keys())
assert len(bool_trans_names) == len(translations_names)
# Check translation files structure
default_dict: dict = load_json_file(
default_dict = load_json_file(
path.join(TRANS_RELATIVE_PATH, integration_lang_list[0]))
for name in list(integration_lang_list)[1:]:
compare_dict: dict = load_json_file(
compare_dict = load_json_file(
path.join(TRANS_RELATIVE_PATH, name))
if not compare_dict_structure(default_dict, compare_dict):
_LOGGER.info(
@ -255,7 +248,7 @@ def test_miot_lang_integrity():
default_dict = load_json_file(
path.join(MIOT_I18N_RELATIVE_PATH, integration_lang_list[0]))
for name in list(integration_lang_list)[1:]:
compare_dict: dict = load_json_file(
compare_dict = load_json_file(
path.join(MIOT_I18N_RELATIVE_PATH, name))
if not compare_dict_structure(default_dict, compare_dict):
_LOGGER.info(
@ -272,19 +265,13 @@ def test_miot_data_sort():
'INTEGRATION_LANGUAGES not sorted, correct order\r\n'
f'{list(sort_langs.keys())}')
assert json.dumps(
load_json_file(file_path=SPEC_BOOL_TRANS_FILE)) == json.dumps(
load_yaml_file(file_path=SPEC_BOOL_TRANS_FILE)) == json.dumps(
sort_bool_trans(file_path=SPEC_BOOL_TRANS_FILE)), (
f'{SPEC_BOOL_TRANS_FILE} not sorted, goto project root path'
' and run the following command sorting, ',
'pytest -s -v -m update ./test/check_rule_format.py')
assert json.dumps(
load_json_file(file_path=SPEC_MULTI_LANG_FILE)) == json.dumps(
sort_multi_lang(file_path=SPEC_MULTI_LANG_FILE)), (
f'{SPEC_MULTI_LANG_FILE} not sorted, goto project root path'
' and run the following command sorting, ',
'pytest -s -v -m update ./test/check_rule_format.py')
assert json.dumps(
load_json_file(file_path=SPEC_FILTER_FILE)) == json.dumps(
load_yaml_file(file_path=SPEC_FILTER_FILE)) == json.dumps(
sort_spec_filter(file_path=SPEC_FILTER_FILE)), (
f'{SPEC_FILTER_FILE} not sorted, goto project root path'
' and run the following command sorting, ',
@ -294,11 +281,8 @@ def test_miot_data_sort():
@pytest.mark.update
def test_sort_spec_data():
sort_data: dict = sort_bool_trans(file_path=SPEC_BOOL_TRANS_FILE)
save_json_file(file_path=SPEC_BOOL_TRANS_FILE, data=sort_data)
save_yaml_file(file_path=SPEC_BOOL_TRANS_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_BOOL_TRANS_FILE)
sort_data = sort_multi_lang(file_path=SPEC_MULTI_LANG_FILE)
save_json_file(file_path=SPEC_MULTI_LANG_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_MULTI_LANG_FILE)
sort_data = sort_spec_filter(file_path=SPEC_FILTER_FILE)
save_json_file(file_path=SPEC_FILTER_FILE, data=sort_data)
save_yaml_file(file_path=SPEC_FILTER_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_FILTER_FILE)