mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-10-12 10:28:01 +00:00
Move tests folder to top level of project (#1242)
This commit is contained in:
136
tests/test_childdevice.py
Normal file
136
tests/test_childdevice.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import inspect
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
|
||||
from kasa import Device
|
||||
from kasa.device_type import DeviceType
|
||||
from kasa.smart.smartchilddevice import SmartChildDevice
|
||||
from kasa.smart.smartdevice import NON_HUB_PARENT_ONLY_MODULES
|
||||
from kasa.smartprotocol import _ChildProtocolWrapper
|
||||
|
||||
from .conftest import (
|
||||
parametrize,
|
||||
parametrize_combine,
|
||||
parametrize_subtract,
|
||||
strip_iot,
|
||||
strip_smart,
|
||||
)
|
||||
|
||||
has_children_smart = parametrize(
|
||||
"has children", component_filter="control_child", protocol_filter={"SMART"}
|
||||
)
|
||||
hub_smart = parametrize(
|
||||
"smart hub", device_type_filter=[DeviceType.Hub], protocol_filter={"SMART"}
|
||||
)
|
||||
non_hub_parent_smart = parametrize_subtract(has_children_smart, hub_smart)
|
||||
|
||||
has_children = parametrize_combine([has_children_smart, strip_iot])
|
||||
|
||||
|
||||
@strip_smart
|
||||
def test_childdevice_init(dev, dummy_protocol, mocker):
|
||||
"""Test that child devices get initialized and use protocol wrapper."""
|
||||
assert len(dev.children) > 0
|
||||
|
||||
first = dev.children[0]
|
||||
assert isinstance(first.protocol, _ChildProtocolWrapper)
|
||||
|
||||
assert first._info["category"] == "plug.powerstrip.sub-plug"
|
||||
assert "position" in first._info
|
||||
|
||||
|
||||
@strip_smart
|
||||
async def test_childdevice_update(dev, dummy_protocol, mocker):
|
||||
"""Test that parent update updates children."""
|
||||
child_info = dev.internal_state["get_child_device_list"]
|
||||
child_list = child_info["child_device_list"]
|
||||
|
||||
assert len(dev.children) == child_info["sum"]
|
||||
first = dev.children[0]
|
||||
|
||||
await dev.update()
|
||||
|
||||
assert dev._info != first._info
|
||||
assert child_list[0] == first._info
|
||||
|
||||
|
||||
@strip_smart
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 11),
|
||||
reason="exceptiongroup requires python3.11+",
|
||||
)
|
||||
async def test_childdevice_properties(dev: SmartChildDevice):
|
||||
"""Check that accessing childdevice properties do not raise exceptions."""
|
||||
assert len(dev.children) > 0
|
||||
|
||||
first = dev.children[0]
|
||||
|
||||
# children do not have children
|
||||
assert not first.children
|
||||
|
||||
def _test_property_getters():
|
||||
"""Try accessing all properties and return a list of encountered exceptions."""
|
||||
exceptions = []
|
||||
properties = inspect.getmembers(
|
||||
first.__class__, lambda o: isinstance(o, property)
|
||||
)
|
||||
for prop in properties:
|
||||
name, _ = prop
|
||||
# Skip emeter and time properties
|
||||
# TODO: needs API cleanup, emeter* should probably be removed in favor
|
||||
# of access through features/modules, handling of time* needs decision.
|
||||
if (
|
||||
name.startswith("emeter_")
|
||||
or name.startswith("time")
|
||||
or name.startswith("fan")
|
||||
or name.startswith("color")
|
||||
or name.startswith("brightness")
|
||||
or name.startswith("valid_temperature_range")
|
||||
or name.startswith("hsv")
|
||||
or name.startswith("effect")
|
||||
):
|
||||
continue
|
||||
try:
|
||||
_ = getattr(first, name)
|
||||
except Exception as ex:
|
||||
exceptions.append(ex)
|
||||
|
||||
return exceptions
|
||||
|
||||
exceptions = list(_test_property_getters())
|
||||
if exceptions:
|
||||
raise ExceptionGroup("Accessing child properties caused exceptions", exceptions)
|
||||
|
||||
|
||||
@non_hub_parent_smart
|
||||
async def test_parent_only_modules(dev, dummy_protocol, mocker):
|
||||
"""Test that parent only modules are not available on children."""
|
||||
for child in dev.children:
|
||||
for module in NON_HUB_PARENT_ONLY_MODULES:
|
||||
assert module not in [type(module) for module in child.modules.values()]
|
||||
|
||||
|
||||
@has_children
|
||||
async def test_parent_property(dev: Device):
|
||||
"""Test a child device exposes it's parent."""
|
||||
if not dev.children:
|
||||
pytest.skip(f"Device {dev} fixture does not have any children")
|
||||
|
||||
assert dev.parent is None
|
||||
for child in dev.children:
|
||||
assert child.parent == dev
|
||||
|
||||
|
||||
@has_children_smart
|
||||
async def test_child_time(dev: Device, freezer: FrozenDateTimeFactory):
|
||||
"""Test a child device gets the time from it's parent module."""
|
||||
if not dev.children:
|
||||
pytest.skip(f"Device {dev} fixture does not have any children")
|
||||
|
||||
fallback_time = datetime.now(timezone.utc).astimezone().replace(microsecond=0)
|
||||
assert dev.parent is None
|
||||
for child in dev.children:
|
||||
assert child.time != fallback_time
|
Reference in New Issue
Block a user