mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 19:09:45 +00:00
157 lines
4.8 KiB
Python
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
|