"""Tests for the Sonos Media Player platform.""" import logging import pytest from homeassistant.components.media_player import ( DOMAIN as MP_DOMAIN, SERVICE_PLAY_MEDIA, ) from homeassistant.const import STATE_IDLE from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import ( CONNECTION_NETWORK_MAC, CONNECTION_UPNP, DeviceRegistry, ) from .conftest import SoCoMockFactory async def test_device_registry( hass: HomeAssistant, device_registry: DeviceRegistry, async_autosetup_sonos, soco ) -> None: """Test sonos device registered in the device registry.""" reg_device = device_registry.async_get_device( identifiers={("sonos", "RINCON_test")} ) assert reg_device is not None assert reg_device.model == "Model Name" assert reg_device.sw_version == "13.1" assert reg_device.connections == { (CONNECTION_NETWORK_MAC, "00:11:22:33:44:55"), (CONNECTION_UPNP, "uuid:RINCON_test"), } assert reg_device.manufacturer == "Sonos" assert reg_device.name == "Zone A" # Default device provides battery info, area should not be suggested assert reg_device.suggested_area is None async def test_device_registry_not_portable( hass: HomeAssistant, device_registry: DeviceRegistry, async_setup_sonos, soco ) -> None: """Test non-portable sonos device registered in the device registry to ensure area suggested.""" soco.get_battery_info.return_value = {} await async_setup_sonos() reg_device = device_registry.async_get_device( identifiers={("sonos", "RINCON_test")} ) assert reg_device is not None assert reg_device.suggested_area == "Zone A" async def test_entity_basic( hass: HomeAssistant, async_autosetup_sonos, discover ) -> None: """Test basic state and attributes.""" state = hass.states.get("media_player.zone_a") assert state.state == STATE_IDLE attributes = state.attributes assert attributes["friendly_name"] == "Zone A" assert attributes["is_volume_muted"] is False assert attributes["volume_level"] == 0.19 class _MockMusicServiceItem: """Mocks a Soco MusicServiceItem.""" def __init__( self, title: str, item_id: str, parent_id: str, item_class: str, ) -> None: """Initialize the mock item.""" self.title = title self.item_id = item_id self.item_class = item_class self.parent_id = parent_id def get_uri(self) -> str: """Return URI.""" return self.item_id.replace("S://", "x-file-cifs://") _mock_playlists = [ _MockMusicServiceItem( "playlist1", "S://192.168.1.68/music/iTunes/iTunes%20Music%20Library.xml#GUID_1", "A:PLAYLISTS", "object.container.playlistContainer", ), _MockMusicServiceItem( "playlist2", "S://192.168.1.68/music/iTunes/iTunes%20Music%20Library.xml#GUID_2", "A:PLAYLISTS", "object.container.playlistContainer", ), ] @pytest.mark.parametrize( ("media_content_id", "expected_item_id"), [ ( _mock_playlists[0].item_id, _mock_playlists[0].item_id, ), ( f"S:{_mock_playlists[1].title}", _mock_playlists[1].item_id, ), ], ) async def test_play_media_music_library_playlist( hass: HomeAssistant, soco_factory: SoCoMockFactory, async_autosetup_sonos, discover, media_content_id, expected_item_id, ) -> None: """Test that playlists can be found by id or title.""" soco_mock = soco_factory.mock_list.get("192.168.42.2") soco_mock.music_library.get_playlists.return_value = _mock_playlists await hass.services.async_call( MP_DOMAIN, SERVICE_PLAY_MEDIA, { "entity_id": "media_player.zone_a", "media_content_type": "playlist", "media_content_id": media_content_id, }, blocking=True, ) assert soco_mock.clear_queue.call_count == 1 assert soco_mock.add_to_queue.call_count == 1 assert soco_mock.add_to_queue.call_args_list[0].args[0].item_id == expected_item_id assert soco_mock.play_from_queue.call_count == 1 async def test_play_media_music_library_playlist_dne( hass: HomeAssistant, soco_factory: SoCoMockFactory, async_autosetup_sonos, caplog: pytest.LogCaptureFixture, ) -> None: """Test error handling when attempting to play a non-existent playlist .""" media_content_id = "S:nonexistent" soco_mock = soco_factory.mock_list.get("192.168.42.2") soco_mock.music_library.get_playlists.return_value = _mock_playlists with caplog.at_level(logging.ERROR): caplog.clear() await hass.services.async_call( MP_DOMAIN, SERVICE_PLAY_MEDIA, { "entity_id": "media_player.zone_a", "media_content_type": "playlist", "media_content_id": media_content_id, }, blocking=True, ) assert soco_mock.play_uri.call_count == 0 assert media_content_id in caplog.text assert "playlist" in caplog.text