mirror of
https://github.com/home-assistant/core
synced 2024-10-05 17:38:03 +00:00
Add JSON support to load_fixture (#88076)
* Add JSON support to load_fixture * More tests * Remove lru_cache on load_json
This commit is contained in:
parent
bc2b35765e
commit
8c821c8969
|
@ -18,6 +18,8 @@ JsonValueType = (
|
|||
dict[str, "JsonValueType"] | list["JsonValueType"] | str | int | float | bool | None
|
||||
)
|
||||
"""Any data that can be returned by the standard JSON deserializing process."""
|
||||
JsonArrayType = list[JsonValueType]
|
||||
"""List that can be returned by the standard JSON deserializing process."""
|
||||
JsonObjectType = dict[str, JsonValueType]
|
||||
"""Dictionary that can be returned by the standard JSON deserializing process."""
|
||||
|
||||
|
@ -34,6 +36,15 @@ json_loads = orjson.loads
|
|||
"""Parse JSON data."""
|
||||
|
||||
|
||||
def json_loads_array(__obj: bytes | bytearray | memoryview | str) -> JsonArrayType:
|
||||
"""Parse JSON data and ensure result is a list."""
|
||||
value: JsonValueType = json_loads(__obj)
|
||||
# Avoid isinstance overhead as we are not interested in list subclasses
|
||||
if type(value) is list: # pylint: disable=unidiomatic-typecheck
|
||||
return value
|
||||
raise ValueError(f"Expected JSON to be parsed as a list got {type(value)}")
|
||||
|
||||
|
||||
def json_loads_object(__obj: bytes | bytearray | memoryview | str) -> JsonObjectType:
|
||||
"""Parse JSON data and ensure result is a dictionary."""
|
||||
value: JsonValueType = json_loads(__obj)
|
||||
|
|
|
@ -67,6 +67,14 @@ from homeassistant.helpers.typing import ConfigType, StateType
|
|||
from homeassistant.setup import setup_component
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
import homeassistant.util.dt as date_util
|
||||
from homeassistant.util.json import (
|
||||
JsonArrayType,
|
||||
JsonObjectType,
|
||||
JsonValueType,
|
||||
json_loads,
|
||||
json_loads_array,
|
||||
json_loads_object,
|
||||
)
|
||||
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||
import homeassistant.util.uuid as uuid_util
|
||||
import homeassistant.util.yaml.loader as yaml_loader
|
||||
|
@ -428,6 +436,27 @@ def load_fixture(filename: str, integration: str | None = None) -> str:
|
|||
return get_fixture_path(filename, integration).read_text()
|
||||
|
||||
|
||||
def load_json_value_fixture(
|
||||
filename: str, integration: str | None = None
|
||||
) -> JsonValueType:
|
||||
"""Load a JSON value from a fixture."""
|
||||
return json_loads(load_fixture(filename, integration))
|
||||
|
||||
|
||||
def load_json_array_fixture(
|
||||
filename: str, integration: str | None = None
|
||||
) -> JsonArrayType:
|
||||
"""Load a JSON array from a fixture."""
|
||||
return json_loads_array(load_fixture(filename, integration))
|
||||
|
||||
|
||||
def load_json_object_fixture(
|
||||
filename: str, integration: str | None = None
|
||||
) -> JsonObjectType:
|
||||
"""Load a JSON object from a fixture."""
|
||||
return json_loads_object(load_fixture(filename, integration))
|
||||
|
||||
|
||||
def mock_state_change_event(
|
||||
hass: HomeAssistant, new_state: State, old_state: State | None = None
|
||||
) -> None:
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
"""Tests for AccuWeather."""
|
||||
import json
|
||||
from unittest.mock import PropertyMock, patch
|
||||
|
||||
from homeassistant.components.accuweather.const import DOMAIN
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
load_json_array_fixture,
|
||||
load_json_object_fixture,
|
||||
)
|
||||
|
||||
|
||||
async def init_integration(
|
||||
|
@ -28,8 +31,8 @@ async def init_integration(
|
|||
options=options,
|
||||
)
|
||||
|
||||
current = json.loads(load_fixture("accuweather/current_conditions_data.json"))
|
||||
forecast = json.loads(load_fixture("accuweather/forecast_data.json"))
|
||||
current = load_json_object_fixture("accuweather/current_conditions_data.json")
|
||||
forecast = load_json_array_fixture("accuweather/forecast_data.json")
|
||||
|
||||
if unsupported_icon:
|
||||
current["WeatherIcon"] = 999
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""Define tests for the AccuWeather config flow."""
|
||||
import json
|
||||
from unittest.mock import PropertyMock, patch
|
||||
|
||||
from accuweather import ApiError, InvalidApiKeyError, RequestsExceededError
|
||||
|
@ -10,7 +9,7 @@ from homeassistant.config_entries import SOURCE_USER
|
|||
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
from tests.common import MockConfigEntry, load_json_object_fixture
|
||||
|
||||
VALID_CONFIG = {
|
||||
CONF_NAME: "abcd",
|
||||
|
@ -99,7 +98,7 @@ async def test_integration_already_exists(hass: HomeAssistant) -> None:
|
|||
"""Test we only allow a single config flow."""
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather._async_get_data",
|
||||
return_value=json.loads(load_fixture("accuweather/location_data.json")),
|
||||
return_value=load_json_object_fixture("accuweather/location_data.json"),
|
||||
):
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
|
@ -121,7 +120,7 @@ async def test_create_entry(hass: HomeAssistant) -> None:
|
|||
"""Test that the user step works."""
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather._async_get_data",
|
||||
return_value=json.loads(load_fixture("accuweather/location_data.json")),
|
||||
return_value=load_json_object_fixture("accuweather/location_data.json"),
|
||||
), patch(
|
||||
"homeassistant.components.accuweather.async_setup_entry", return_value=True
|
||||
):
|
||||
|
@ -150,11 +149,11 @@ async def test_options_flow(hass: HomeAssistant) -> None:
|
|||
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather._async_get_data",
|
||||
return_value=json.loads(load_fixture("accuweather/location_data.json")),
|
||||
return_value=load_json_object_fixture("accuweather/location_data.json"),
|
||||
), patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.async_get_current_conditions",
|
||||
return_value=json.loads(
|
||||
load_fixture("accuweather/current_conditions_data.json")
|
||||
return_value=load_json_object_fixture(
|
||||
"accuweather/current_conditions_data.json"
|
||||
),
|
||||
), patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.async_get_forecast"
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
"""Test AccuWeather diagnostics."""
|
||||
import json
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import init_integration
|
||||
|
||||
from tests.common import load_fixture
|
||||
from tests.common import load_json_object_fixture
|
||||
from tests.components.diagnostics import get_diagnostics_for_config_entry
|
||||
from tests.typing import ClientSessionGenerator
|
||||
|
||||
|
@ -16,9 +15,10 @@ async def test_entry_diagnostics(
|
|||
"""Test config entry diagnostics."""
|
||||
entry = await init_integration(hass)
|
||||
|
||||
coordinator_data = json.loads(
|
||||
load_fixture("current_conditions_data.json", "accuweather")
|
||||
coordinator_data = load_json_object_fixture(
|
||||
"current_conditions_data.json", "accuweather"
|
||||
)
|
||||
|
||||
coordinator_data["forecast"] = {}
|
||||
|
||||
result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""Test init of AccuWeather integration."""
|
||||
from datetime import timedelta
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
from accuweather import ApiError
|
||||
|
@ -13,7 +12,12 @@ from homeassistant.util.dt import utcnow
|
|||
|
||||
from . import init_integration
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_array_fixture,
|
||||
load_json_object_fixture,
|
||||
)
|
||||
|
||||
|
||||
async def test_async_setup_entry(hass: HomeAssistant) -> None:
|
||||
|
@ -69,7 +73,7 @@ async def test_update_interval(hass: HomeAssistant) -> None:
|
|||
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
current = json.loads(load_fixture("accuweather/current_conditions_data.json"))
|
||||
current = load_json_object_fixture("accuweather/current_conditions_data.json")
|
||||
future = utcnow() + timedelta(minutes=40)
|
||||
|
||||
with patch(
|
||||
|
@ -90,8 +94,8 @@ async def test_update_interval_forecast(hass: HomeAssistant) -> None:
|
|||
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
current = json.loads(load_fixture("accuweather/current_conditions_data.json"))
|
||||
forecast = json.loads(load_fixture("accuweather/forecast_data.json"))
|
||||
current = load_json_object_fixture("accuweather/current_conditions_data.json")
|
||||
forecast = load_json_array_fixture("accuweather/forecast_data.json")
|
||||
future = utcnow() + timedelta(minutes=80)
|
||||
|
||||
with patch(
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""Test sensor of AccuWeather integration."""
|
||||
from datetime import timedelta
|
||||
import json
|
||||
from unittest.mock import PropertyMock, patch
|
||||
|
||||
from homeassistant.components.accuweather.const import ATTRIBUTION, DOMAIN
|
||||
|
@ -35,7 +34,11 @@ from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
|||
|
||||
from . import init_integration
|
||||
|
||||
from tests.common import async_fire_time_changed, load_fixture
|
||||
from tests.common import (
|
||||
async_fire_time_changed,
|
||||
load_json_array_fixture,
|
||||
load_json_object_fixture,
|
||||
)
|
||||
|
||||
|
||||
async def test_sensor_without_forecast(hass: HomeAssistant) -> None:
|
||||
|
@ -684,8 +687,8 @@ async def test_availability(hass: HomeAssistant) -> None:
|
|||
future = utcnow() + timedelta(minutes=120)
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.async_get_current_conditions",
|
||||
return_value=json.loads(
|
||||
load_fixture("accuweather/current_conditions_data.json")
|
||||
return_value=load_json_object_fixture(
|
||||
"accuweather/current_conditions_data.json"
|
||||
),
|
||||
), patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.requests_remaining",
|
||||
|
@ -707,8 +710,8 @@ async def test_manual_update_entity(hass: HomeAssistant) -> None:
|
|||
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
current = json.loads(load_fixture("accuweather/current_conditions_data.json"))
|
||||
forecast = json.loads(load_fixture("accuweather/forecast_data.json"))
|
||||
current = load_json_object_fixture("accuweather/current_conditions_data.json")
|
||||
forecast = load_json_array_fixture("accuweather/forecast_data.json")
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.async_get_current_conditions",
|
||||
|
@ -755,8 +758,8 @@ async def test_state_update(hass: HomeAssistant) -> None:
|
|||
|
||||
future = utcnow() + timedelta(minutes=60)
|
||||
|
||||
current_condition = json.loads(
|
||||
load_fixture("accuweather/current_conditions_data.json")
|
||||
current_condition = load_json_object_fixture(
|
||||
"accuweather/current_conditions_data.json"
|
||||
)
|
||||
current_condition["Ceiling"]["Metric"]["Value"] = 3300
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""Test weather of AccuWeather integration."""
|
||||
from datetime import timedelta
|
||||
import json
|
||||
from unittest.mock import PropertyMock, patch
|
||||
|
||||
from homeassistant.components.accuweather.const import ATTRIBUTION
|
||||
|
@ -30,7 +29,11 @@ from homeassistant.util.dt import utcnow
|
|||
|
||||
from . import init_integration
|
||||
|
||||
from tests.common import async_fire_time_changed, load_fixture
|
||||
from tests.common import (
|
||||
async_fire_time_changed,
|
||||
load_json_array_fixture,
|
||||
load_json_object_fixture,
|
||||
)
|
||||
|
||||
|
||||
async def test_weather_without_forecast(hass: HomeAssistant) -> None:
|
||||
|
@ -111,8 +114,8 @@ async def test_availability(hass: HomeAssistant) -> None:
|
|||
future = utcnow() + timedelta(minutes=120)
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.async_get_current_conditions",
|
||||
return_value=json.loads(
|
||||
load_fixture("accuweather/current_conditions_data.json")
|
||||
return_value=load_json_object_fixture(
|
||||
"accuweather/current_conditions_data.json"
|
||||
),
|
||||
), patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.requests_remaining",
|
||||
|
@ -134,8 +137,8 @@ async def test_manual_update_entity(hass: HomeAssistant) -> None:
|
|||
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
current = json.loads(load_fixture("accuweather/current_conditions_data.json"))
|
||||
forecast = json.loads(load_fixture("accuweather/forecast_data.json"))
|
||||
current = load_json_object_fixture("accuweather/current_conditions_data.json")
|
||||
forecast = load_json_array_fixture("accuweather/forecast_data.json")
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.accuweather.AccuWeather.async_get_current_conditions",
|
||||
|
|
|
@ -15,6 +15,7 @@ from homeassistant.helpers.json import JSONEncoder as DefaultHASSJSONEncoder
|
|||
from homeassistant.util.json import (
|
||||
SerializationError,
|
||||
find_paths_unserializable_data,
|
||||
json_loads_array,
|
||||
json_loads_object,
|
||||
load_json,
|
||||
save_json,
|
||||
|
@ -194,6 +195,23 @@ def test_find_unserializable_data() -> None:
|
|||
) == {"$(BadData).bla": bad_data}
|
||||
|
||||
|
||||
def test_json_loads_array() -> None:
|
||||
"""Test json_loads_array validates result."""
|
||||
assert json_loads_array('[{"c":1.2}]') == [{"c": 1.2}]
|
||||
with pytest.raises(
|
||||
ValueError, match="Expected JSON to be parsed as a list got <class 'dict'>"
|
||||
):
|
||||
json_loads_array("{}")
|
||||
with pytest.raises(
|
||||
ValueError, match="Expected JSON to be parsed as a list got <class 'bool'>"
|
||||
):
|
||||
json_loads_array("true")
|
||||
with pytest.raises(
|
||||
ValueError, match="Expected JSON to be parsed as a list got <class 'NoneType'>"
|
||||
):
|
||||
json_loads_array("null")
|
||||
|
||||
|
||||
def test_json_loads_object() -> None:
|
||||
"""Test json_loads_object validates result."""
|
||||
assert json_loads_object('{"c":1.2}') == {"c": 1.2}
|
||||
|
|
Loading…
Reference in a new issue