Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions tests/components/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@

from .conversation import MockAgent
from .device_tracker.common import MockScanner
from .infrared.common import MockInfraredEntity
from .light.common import MockLight
from .radio_frequency.common import MockRadioFrequencyEntity
from .sensor.common import MockSensor
Expand Down Expand Up @@ -224,6 +225,25 @@ async def mock_rf_entity_fixture(
return await mock_rf_entity_fixture_helper(hass)


# Infrared test fixtures
@pytest.fixture(name="init_infrared")
async def init_infrared_fixture(hass: HomeAssistant) -> None:
"""Set up the Infrared integration for testing."""
from .infrared.common import init_infrared_fixture_helper # noqa: PLC0415

await init_infrared_fixture_helper(hass)


@pytest.fixture(name="mock_infrared_entity")
async def mock_infrared_entity_fixture(
hass: HomeAssistant, init_infrared: None
) -> MockInfraredEntity:
"""Return a mock infrared entity."""
from .infrared.common import mock_infrared_entity_fixture_helper # noqa: PLC0415

return await mock_infrared_entity_fixture_helper(hass)


@pytest.fixture(scope="session", autouse=find_spec("haffmpeg") is not None)
def prevent_ffmpeg_subprocess() -> Generator[None]:
"""If installed, prevent ffmpeg from creating a subprocess."""
Expand Down
2 changes: 2 additions & 0 deletions tests/components/infrared/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
"""Tests for the Infrared integration."""

ENTITY_ID = "infrared.test_ir_transmitter"
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
"""Common fixtures for the Infrared tests."""
"""Common test tools for the Infrared integration."""

from infrared_protocols.commands import Command as InfraredCommand
import pytest

from homeassistant.components.infrared import InfraredEntity
from homeassistant.components.infrared import DATA_COMPONENT, InfraredEntity
from homeassistant.components.infrared.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component


@pytest.fixture
async def init_integration(hass: HomeAssistant) -> None:
"""Set up the Infrared integration for testing."""
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()


class MockInfraredEntity(InfraredEntity):
"""Mock infrared entity for testing."""

Expand All @@ -32,7 +24,17 @@ async def async_send_command(self, command: InfraredCommand) -> None:
self.send_command_calls.append(command)


@pytest.fixture
def mock_infrared_entity() -> MockInfraredEntity:
"""Return a mock infrared entity."""
return MockInfraredEntity("test_ir_transmitter")
async def init_infrared_fixture_helper(hass: HomeAssistant) -> None:
"""Set up the Infrared integration for testing."""
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()


async def mock_infrared_entity_fixture_helper(
hass: HomeAssistant,
) -> MockInfraredEntity:
"""Add a mock infrared entity to the running integration."""
entity = MockInfraredEntity("test_ir_transmitter")
component = hass.data[DATA_COMPONENT]
await component.async_add_entities([entity])
return entity
46 changes: 15 additions & 31 deletions tests/components/infrared/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util

from .conftest import MockInfraredEntity
from . import ENTITY_ID
from .common import MockInfraredEntity

from tests.common import mock_restore_cache

Expand All @@ -28,61 +29,46 @@ async def test_get_entities_integration_setup(hass: HomeAssistant) -> None:
assert async_get_emitters(hass) == []


@pytest.mark.usefixtures("init_integration")
@pytest.mark.usefixtures("init_infrared")
async def test_get_entities_empty(hass: HomeAssistant) -> None:
"""Test getting entities when none are registered."""
assert async_get_emitters(hass) == []


@pytest.mark.usefixtures("init_integration")
async def test_infrared_entity_initial_state(
hass: HomeAssistant, mock_infrared_entity: MockInfraredEntity
) -> None:
@pytest.mark.usefixtures("mock_infrared_entity")
async def test_infrared_entity_initial_state(hass: HomeAssistant) -> None:
"""Test infrared entity has no state before any command is sent."""
component = hass.data[DATA_COMPONENT]
await component.async_add_entities([mock_infrared_entity])

state = hass.states.get("infrared.test_ir_transmitter")
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state == STATE_UNKNOWN


@pytest.mark.usefixtures("init_integration")
async def test_async_send_command_success(
hass: HomeAssistant,
mock_infrared_entity: MockInfraredEntity,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sending command via async_send_command helper."""
# Add the mock entity to the component
component = hass.data[DATA_COMPONENT]
await component.async_add_entities([mock_infrared_entity])

# Freeze time so we can verify the state update
now = dt_util.utcnow()
freezer.move_to(now)

command = NECCommand(address=0x04FB, command=0x08F7, modulation=38000)
await async_send_command(hass, mock_infrared_entity.entity_id, command)
await async_send_command(hass, ENTITY_ID, command)

assert len(mock_infrared_entity.send_command_calls) == 1
assert mock_infrared_entity.send_command_calls[0] is command

state = hass.states.get("infrared.test_ir_transmitter")
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state == now.isoformat(timespec="milliseconds")


@pytest.mark.usefixtures("init_integration")
async def test_async_send_command_error_does_not_update_state(
hass: HomeAssistant,
mock_infrared_entity: MockInfraredEntity,
) -> None:
"""Test that state is not updated when async_send_command raises an error."""
component = hass.data[DATA_COMPONENT]
await component.async_add_entities([mock_infrared_entity])

state = hass.states.get("infrared.test_ir_transmitter")
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state == STATE_UNKNOWN

Expand All @@ -93,15 +79,14 @@ async def test_async_send_command_error_does_not_update_state(
)

with pytest.raises(HomeAssistantError, match="Transmission failed"):
await async_send_command(hass, mock_infrared_entity.entity_id, command)
await async_send_command(hass, ENTITY_ID, command)

# Verify state was not updated after the error
state = hass.states.get("infrared.test_ir_transmitter")
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state == STATE_UNKNOWN


@pytest.mark.usefixtures("init_integration")
@pytest.mark.usefixtures("init_infrared")
async def test_async_send_command_entity_not_found(hass: HomeAssistant) -> None:
"""Test async_send_command raises error when entity not found."""
command = NECCommand(
Expand Down Expand Up @@ -134,19 +119,18 @@ async def test_async_send_command_component_not_loaded(hass: HomeAssistant) -> N
)
async def test_infrared_entity_state_restore(
hass: HomeAssistant,
mock_infrared_entity: MockInfraredEntity,
restored_value: str,
expected_state: str,
) -> None:
"""Test infrared entity state restore."""
mock_restore_cache(hass, [State("infrared.test_ir_transmitter", restored_value)])
mock_restore_cache(hass, [State(ENTITY_ID, restored_value)])

assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()

component = hass.data[DATA_COMPONENT]
await component.async_add_entities([mock_infrared_entity])
await component.async_add_entities([MockInfraredEntity("test_ir_transmitter")])

state = hass.states.get("infrared.test_ir_transmitter")
state = hass.states.get(ENTITY_ID)
assert state is not None
assert state.state == expected_state
39 changes: 2 additions & 37 deletions tests/components/lg_infrared/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@
from collections.abc import Generator
from unittest.mock import patch

from infrared_protocols.commands import Command as InfraredCommand
import pytest

from homeassistant.components.infrared import (
DATA_COMPONENT as INFRARED_DATA_COMPONENT,
DOMAIN as INFRARED_DOMAIN,
InfraredEntity,
)
from homeassistant.components.lg_infrared import PLATFORMS
from homeassistant.components.lg_infrared.const import (
CONF_DEVICE_TYPE,
Expand All @@ -20,27 +14,10 @@
)
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component

from tests.common import MockConfigEntry

MOCK_INFRARED_ENTITY_ID = "infrared.test_ir_transmitter"


class MockInfraredEntity(InfraredEntity):
"""Mock infrared entity for testing."""

_attr_has_entity_name = True
_attr_name = "Test IR transmitter"

def __init__(self, unique_id: str) -> None:
"""Initialize mock entity."""
self._attr_unique_id = unique_id
self.send_command_calls: list[InfraredCommand] = []

async def async_send_command(self, command: InfraredCommand) -> None:
"""Mock send command."""
self.send_command_calls.append(command)
from tests.components.infrared import ENTITY_ID as MOCK_INFRARED_ENTITY_ID
from tests.components.infrared.common import MockInfraredEntity


@pytest.fixture
Expand All @@ -58,12 +35,6 @@ def mock_config_entry() -> MockConfigEntry:
)


@pytest.fixture
def mock_infrared_entity() -> MockInfraredEntity:
"""Return a mock infrared entity."""
return MockInfraredEntity("test_ir_transmitter")


@pytest.fixture
def platforms() -> list[Platform]:
"""Return platforms to set up."""
Expand Down Expand Up @@ -94,12 +65,6 @@ async def init_integration(
platforms: list[Platform],
) -> MockConfigEntry:
"""Set up the LG Infrared integration for testing."""
assert await async_setup_component(hass, INFRARED_DOMAIN, {})
await hass.async_block_till_done()

infrared_component = hass.data[INFRARED_DATA_COMPONENT]
await infrared_component.async_add_entities([mock_infrared_entity])

mock_config_entry.add_to_hass(hass)

with patch("homeassistant.components.lg_infrared.PLATFORMS", platforms):
Expand Down
2 changes: 1 addition & 1 deletion tests/components/lg_infrared/test_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er

from .conftest import MockInfraredEntity
from .utils import check_availability_follows_ir_entity

from tests.common import MockConfigEntry, snapshot_platform
from tests.components.infrared.common import MockInfraredEntity


@pytest.fixture
Expand Down
30 changes: 5 additions & 25 deletions tests/components/lg_infrared/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

import pytest

from homeassistant.components.infrared import (
DATA_COMPONENT as INFRARED_DATA_COMPONENT,
DOMAIN as INFRARED_DOMAIN,
)
from homeassistant.components.lg_infrared.const import (
CONF_DEVICE_TYPE,
CONF_INFRARED_ENTITY_ID,
Expand All @@ -16,26 +12,12 @@
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component

from .conftest import MOCK_INFRARED_ENTITY_ID, MockInfraredEntity

from tests.common import MockConfigEntry
from tests.components.infrared import ENTITY_ID as MOCK_INFRARED_ENTITY_ID


@pytest.fixture
async def setup_infrared(
hass: HomeAssistant, mock_infrared_entity: MockInfraredEntity
) -> None:
"""Set up the infrared component with a mock entity."""
assert await async_setup_component(hass, INFRARED_DOMAIN, {})
await hass.async_block_till_done()

component = hass.data[INFRARED_DATA_COMPONENT]
await component.async_add_entities([mock_infrared_entity])


@pytest.mark.usefixtures("setup_infrared")
@pytest.mark.usefixtures("mock_infrared_entity")
async def test_user_flow_success(
hass: HomeAssistant,
) -> None:
Expand Down Expand Up @@ -64,7 +46,7 @@ async def test_user_flow_success(
assert result["result"].unique_id == f"lg_ir_tv_{MOCK_INFRARED_ENTITY_ID}"


@pytest.mark.usefixtures("setup_infrared")
@pytest.mark.usefixtures("mock_infrared_entity")
async def test_user_flow_already_configured(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
Expand All @@ -89,11 +71,9 @@ async def test_user_flow_already_configured(
assert result["reason"] == "already_configured"


@pytest.mark.usefixtures("init_infrared")
async def test_user_flow_no_emitters(hass: HomeAssistant) -> None:
"""Test user flow aborts when no infrared emitters exist."""
assert await async_setup_component(hass, INFRARED_DOMAIN, {})
await hass.async_block_till_done()

result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
Expand All @@ -102,7 +82,7 @@ async def test_user_flow_no_emitters(hass: HomeAssistant) -> None:
assert result["reason"] == "no_emitters"


@pytest.mark.usefixtures("setup_infrared")
@pytest.mark.usefixtures("mock_infrared_entity")
@pytest.mark.parametrize(
("entity_name", "expected_title"),
[
Expand Down
2 changes: 1 addition & 1 deletion tests/components/lg_infrared/test_media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er

from .conftest import MockInfraredEntity
from .utils import check_availability_follows_ir_entity

from tests.common import MockConfigEntry, snapshot_platform
from tests.components.infrared.common import MockInfraredEntity

MEDIA_PLAYER_ENTITY_ID = "media_player.lg_tv"

Expand Down
2 changes: 1 addition & 1 deletion tests/components/lg_infrared/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant

from .conftest import MOCK_INFRARED_ENTITY_ID
from tests.components.infrared import ENTITY_ID as MOCK_INFRARED_ENTITY_ID


async def check_availability_follows_ir_entity(
Expand Down
Loading