1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-20 19:09:45 +00:00
Files
core/tests/hassfest/test_conditions.py

157 lines
4.8 KiB
Python

"""Tests for hassfest conditions."""
import io
import json
from pathlib import Path
from unittest.mock import patch
import pytest
from homeassistant.util.yaml.loader import parse_yaml
from script.hassfest import conditions
from script.hassfest.model import Config
from . import get_integration
CONDITION_DESCRIPTION_FILENAME = "conditions.yaml"
CONDITION_ICONS_FILENAME = "icons.json"
CONDITION_STRINGS_FILENAME = "strings.json"
CONDITION_DESCRIPTIONS = {
"valid": {
CONDITION_DESCRIPTION_FILENAME: """
_:
target:
entity:
domain: light
fields:
after:
example: sunrise
selector:
select:
options:
- sunrise
- sunset
after_offset:
selector:
time: null
""",
CONDITION_ICONS_FILENAME: {"conditions": {"_": {"condition": "mdi:flash"}}},
CONDITION_STRINGS_FILENAME: {
"conditions": {
"_": {
"name": "Sun",
"description": "When the sun is above/below the horizon",
"fields": {
"after": {"name": "After event", "description": "The event."},
"after_offset": {
"name": "Offset",
"description": "The offset.",
},
},
}
}
},
"errors": [],
},
"yaml_missing_colon": {
CONDITION_DESCRIPTION_FILENAME: """
test:
fields
entity:
selector:
entity:
""",
"errors": ["Invalid conditions.yaml"],
},
"invalid_conditions_schema": {
CONDITION_DESCRIPTION_FILENAME: """
invalid_condition:
fields:
entity:
selector:
invalid_selector: null
""",
"errors": ["Unknown selector type invalid_selector"],
},
"missing_strings_and_icons": {
CONDITION_DESCRIPTION_FILENAME: """
sun:
fields:
after:
example: sunrise
selector:
select:
options:
- sunrise
- sunset
translation_key: after
after_offset:
selector:
time: null
""",
CONDITION_ICONS_FILENAME: {"conditions": {}},
CONDITION_STRINGS_FILENAME: {
"conditions": {
"sun": {
"fields": {
"after_offset": {},
},
}
}
},
"errors": [
"has no icon",
"has no name",
"has no description",
"field after with no name",
"field after with no description",
"field after with a selector with a translation key",
"field after_offset with no name",
"field after_offset with no description",
],
},
}
@pytest.mark.usefixtures("mock_core_integration")
def test_validate(config: Config) -> None:
"""Test validate version with no key."""
def _load_yaml(fname, secrets=None):
domain, yaml_file = fname.split("/")
assert yaml_file == CONDITION_DESCRIPTION_FILENAME
condition_descriptions = CONDITION_DESCRIPTIONS[domain][yaml_file]
with io.StringIO(condition_descriptions) as file:
return parse_yaml(file)
def _patched_path_read_text(path: Path):
domain = path.parent.name
filename = path.name
return json.dumps(CONDITION_DESCRIPTIONS[domain][filename])
integrations = {
domain: get_integration(domain, config) for domain in CONDITION_DESCRIPTIONS
}
with (
patch("script.hassfest.conditions.grep_dir", return_value=True),
patch("pathlib.Path.is_file", return_value=True),
patch("pathlib.Path.read_text", _patched_path_read_text),
patch("annotatedyaml.loader.load_yaml", side_effect=_load_yaml),
):
conditions.validate(integrations, config)
assert not config.errors
for domain, description in CONDITION_DESCRIPTIONS.items():
assert len(integrations[domain].errors) == len(description["errors"]), (
f"Domain '{domain}' has unexpected errors: {integrations[domain].errors}"
)
for error, expected_error in zip(
integrations[domain].errors, description["errors"], strict=True
):
assert expected_error in error.error