Add shared test mocks for the Infrared integration (#170296)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Paulus Schoutsen
2026-05-11 09:46:09 +02:00
committed by GitHub
co-authored by Claude
parent d5f2cd8b17
commit af41b704d5
9 changed files with 63 additions and 110 deletions
+20
View File
@@ -95,6 +95,7 @@ if TYPE_CHECKING:
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
@@ -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."""
+2
View File
@@ -1 +1,3 @@
"""Tests for the Infrared integration."""
ENTITY_ID = "infrared.test_ir_transmitter"
@@ -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."""
@@ -32,7 +24,17 @@ class MockInfraredEntity(InfraredEntity):
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
+15 -31
View File
@@ -18,7 +18,8 @@ from homeassistant.exceptions import HomeAssistantError
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
@@ -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
@@ -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(
@@ -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
+2 -37
View File
@@ -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,
@@ -20,27 +14,10 @@ from homeassistant.components.lg_infrared.const import (
)
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
@@ -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."""
@@ -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):
+1 -1
View File
@@ -9,10 +9,10 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
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
@@ -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,
@@ -16,26 +12,12 @@ from homeassistant.config_entries import SOURCE_USER
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:
@@ -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:
@@ -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}
)
@@ -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"),
[
@@ -21,10 +21,10 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
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"
+1 -1
View File
@@ -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(