diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index 8c21336b59f..e7b3a818f63 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -1,12 +1,11 @@ """The tests for the TTS component.""" from http import HTTPStatus -from unittest.mock import PropertyMock, patch +from typing import Any import pytest import voluptuous as vol from homeassistant.components import media_source, tts -from homeassistant.components.demo.tts import DemoProvider from homeassistant.components.media_player import ( ATTR_MEDIA_ANNOUNCE, ATTR_MEDIA_CONTENT_ID, @@ -18,10 +17,17 @@ from homeassistant.components.media_player import ( from homeassistant.config import async_process_ha_core_config from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.setup import async_setup_component from homeassistant.util.network import normalize_url -from tests.common import assert_setup_component, async_mock_service +from tests.common import ( + MockModule, + assert_setup_component, + async_mock_service, + mock_integration, + mock_platform, +) from tests.typing import ClientSessionGenerator ORIG_WRITE_TAGS = tts.SpeechManager.write_tags @@ -36,10 +42,68 @@ async def get_media_source_url(hass, media_content_id): return resolved.url +SUPPORT_LANGUAGES = ["de", "en", "en_US"] + +DEFAULT_LANG = "en" + + +class MockProvider(tts.Provider): + """Test speech API provider.""" + + def __init__(self, lang: str) -> None: + """Initialize test provider.""" + self._lang = lang + self.name = "Test" + + @property + def default_language(self) -> str: + """Return the default language.""" + return self._lang + + @property + def supported_languages(self) -> list[str]: + """Return list of supported languages.""" + return SUPPORT_LANGUAGES + + @property + def supported_options(self) -> list[str]: + """Return list of supported options like voice, emotions.""" + return ["voice", "age"] + + def get_tts_audio( + self, message: str, language: str, options: dict[str, Any] | None = None + ) -> tts.TtsAudioType: + """Load TTS dat.""" + return ("mp3", b"") + + +class MockTTS: + """A mock TTS platform.""" + + PLATFORM_SCHEMA = tts.PLATFORM_SCHEMA.extend( + {vol.Optional(tts.CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES)} + ) + + def __init__(self, provider=None) -> None: + """Initialize.""" + if provider is None: + provider = MockProvider + self._provider = provider + + async def async_get_engine( + self, + hass: HomeAssistant, + config: ConfigType, + discovery_info: DiscoveryInfoType | None = None, + ) -> tts.Provider: + """Set up a mock speech component.""" + return self._provider(config.get(tts.CONF_LANG, DEFAULT_LANG)) + + @pytest.fixture -def demo_provider(): - """Demo TTS provider.""" - return DemoProvider("en") +def test_provider(): + """Test TTS provider.""" + return MockProvider("en") @pytest.fixture(autouse=True) @@ -52,49 +116,52 @@ async def internal_url_mock(hass): @pytest.fixture -async def setup_tts(hass): +async def mock_tts(hass): """Mock TTS.""" - with patch("homeassistant.components.demo.async_setup", return_value=True): - assert await async_setup_component( - hass, tts.DOMAIN, {"tts": {"platform": "demo"}} - ) - await hass.async_block_till_done() + mock_integration(hass, MockModule(domain="test")) + mock_platform(hass, "test.tts", MockTTS()) -async def test_setup_component_demo(hass: HomeAssistant, setup_tts) -> None: - """Set up the demo platform with defaults.""" - assert hass.services.has_service(tts.DOMAIN, "demo_say") +@pytest.fixture +async def setup_tts(hass, mock_tts): + """Mock TTS.""" + assert await async_setup_component(hass, tts.DOMAIN, {"tts": {"platform": "test"}}) + + +async def test_setup_component(hass: HomeAssistant, setup_tts) -> None: + """Set up a TTS platform with defaults.""" + assert hass.services.has_service(tts.DOMAIN, "test_say") assert hass.services.has_service(tts.DOMAIN, "clear_cache") - assert f"{tts.DOMAIN}.demo" in hass.config.components + assert f"{tts.DOMAIN}.test" in hass.config.components -async def test_setup_component_demo_no_access_cache_folder( - hass: HomeAssistant, mock_init_cache_dir +async def test_setup_component_no_access_cache_folder( + hass: HomeAssistant, mock_init_cache_dir, mock_tts ) -> None: - """Set up the demo platform with defaults.""" - config = {tts.DOMAIN: {"platform": "demo"}} + """Set up a TTS platform with defaults.""" + config = {tts.DOMAIN: {"platform": "test"}} mock_init_cache_dir.side_effect = OSError(2, "No access") assert not await async_setup_component(hass, tts.DOMAIN, config) - assert not hass.services.has_service(tts.DOMAIN, "demo_say") + assert not hass.services.has_service(tts.DOMAIN, "test_say") assert not hass.services.has_service(tts.DOMAIN, "clear_cache") async def test_setup_component_and_test_service( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service.""" + """Set up a TTS platform and call service.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -107,28 +174,28 @@ async def test_setup_component_and_test_service( assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ) await hass.async_block_till_done() assert ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_config_language( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service.""" + """Set up a TTS platform and call service.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo", "language": "de"}} + config = {tts.DOMAIN: {"platform": "test", "language": "de"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -139,31 +206,28 @@ async def test_setup_component_and_test_service_with_config_language( assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3" + == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_test.mp3" ) await hass.async_block_till_done() assert ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_config_language_special( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service with extend language.""" - import homeassistant.components.demo.tts as demo_tts - - demo_tts.SUPPORT_LANGUAGES.append("en_US") + """Set up a TTS platform and call service with extend language.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo", "language": "en_US"}} + config = {tts.DOMAIN: {"platform": "test", "language": "en_US"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -174,38 +238,38 @@ async def test_setup_component_and_test_service_with_config_language_special( assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_demo.mp3" + == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_test.mp3" ) await hass.async_block_till_done() assert ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_wrong_conf_language( - hass: HomeAssistant, + hass: HomeAssistant, mock_tts ) -> None: - """Set up the demo platform and call service with wrong config.""" - config = {tts.DOMAIN: {"platform": "demo", "language": "ru"}} + """Set up a TTS platform and call service with wrong config.""" + config = {tts.DOMAIN: {"platform": "test", "language": "ru"}} with assert_setup_component(0, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) async def test_setup_component_and_test_service_with_service_language( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service.""" + """Set up a TTS platform and call service.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -217,21 +281,21 @@ async def test_setup_component_and_test_service_with_service_language( assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3" + == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_test.mp3" ) await hass.async_block_till_done() assert ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_test.mp3" ).is_file() async def test_setup_component_test_service_with_wrong_service_language( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service.""" + """Set up a TTS platform and call service.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) @@ -239,7 +303,7 @@ async def test_setup_component_test_service_with_wrong_service_language( with pytest.raises(HomeAssistantError): await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -249,24 +313,24 @@ async def test_setup_component_test_service_with_wrong_service_language( ) assert len(calls) == 0 assert not ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_lang_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_lang_-_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_service_options( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service with options.""" + """Set up a TTS platform and call service with options.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -281,32 +345,37 @@ async def test_setup_component_and_test_service_with_service_options( assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == f"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_demo.mp3" + == f"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_test.mp3" ) await hass.async_block_till_done() assert ( empty_cache_dir - / f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_demo.mp3" + / f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_test.mp3" ).is_file() async def test_setup_component_and_test_with_service_options_def( hass: HomeAssistant, empty_cache_dir ) -> None: - """Set up the demo platform and call service with default options.""" + """Set up a TTS platform and call service with default options.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} - with assert_setup_component(1, tts.DOMAIN), patch( - "homeassistant.components.demo.tts.DemoProvider.default_options", - new_callable=PropertyMock(return_value={"voice": "alex"}), - ): + class MockProviderWithDefaults(MockProvider): + @property + def default_options(self): + return {"voice": "alex"} + + mock_integration(hass, MockModule(domain="test")) + mock_platform(hass, "test.tts", MockTTS(MockProviderWithDefaults)) + + with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -320,22 +389,22 @@ async def test_setup_component_and_test_with_service_options_def( assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == f"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_demo.mp3" + == f"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_test.mp3" ) await hass.async_block_till_done() assert ( empty_cache_dir - / f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_demo.mp3" + / f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_service_options_wrong( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service with wrong options.""" + """Set up a TTS platform and call service with wrong options.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) @@ -343,7 +412,7 @@ async def test_setup_component_and_test_service_with_service_options_wrong( with pytest.raises(HomeAssistantError): await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -358,24 +427,24 @@ async def test_setup_component_and_test_service_with_service_options_wrong( await hass.async_block_till_done() assert not ( empty_cache_dir - / f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_demo.mp3" + / f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de_{opt_hash}_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_base_url_set( - hass: HomeAssistant, + hass: HomeAssistant, mock_tts ) -> None: - """Set up the demo platform with ``base_url`` set and call service.""" + """Set up a TTS platform with ``base_url`` set and call service.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo", "base_url": "http://fnord"}} + config = {tts.DOMAIN: {"platform": "test", "base_url": "http://fnord"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -388,24 +457,24 @@ async def test_setup_component_and_test_service_with_base_url_set( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) == "http://fnord" "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491" - "_en_-_demo.mp3" + "_en_-_test.mp3" ) async def test_setup_component_and_test_service_clear_cache( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up the demo platform and call service clear cache.""" + """Set up a TTS platform and call service clear cache.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -417,7 +486,7 @@ async def test_setup_component_and_test_service_clear_cache( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) await hass.async_block_till_done() assert ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ).is_file() await hass.services.async_call( @@ -425,17 +494,17 @@ async def test_setup_component_and_test_service_clear_cache( ) assert not ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ).is_file() async def test_setup_component_and_test_service_with_receive_voice( - hass: HomeAssistant, demo_provider, hass_client: ClientSessionGenerator + hass: HomeAssistant, test_provider, hass_client: ClientSessionGenerator, mock_tts ) -> None: - """Set up the demo platform and call service and receive voice.""" + """Set up a TTS platform and call service and receive voice.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo"}} + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) @@ -444,7 +513,7 @@ async def test_setup_component_and_test_service_with_receive_voice( await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: message, @@ -456,39 +525,39 @@ async def test_setup_component_and_test_service_with_receive_voice( url = await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) client = await hass_client() req = await client.get(url) - _, demo_data = demo_provider.get_tts_audio("bla", "en") - demo_data = tts.SpeechManager.write_tags( - "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3", - demo_data, - demo_provider, + _, tts_data = test_provider.get_tts_audio("bla", "en") + tts_data = tts.SpeechManager.write_tags( + "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3", + tts_data, + test_provider, message, "en", None, ) assert req.status == HTTPStatus.OK - assert await req.read() == demo_data + assert await req.read() == tts_data extension, data = await tts.async_get_media_source_audio( hass, calls[0].data[ATTR_MEDIA_CONTENT_ID] ) assert extension == "mp3" - assert demo_data == data + assert tts_data == data async def test_setup_component_and_test_service_with_receive_voice_german( - hass: HomeAssistant, demo_provider, hass_client: ClientSessionGenerator + hass: HomeAssistant, test_provider, hass_client: ClientSessionGenerator, mock_tts ) -> None: - """Set up the demo platform and call service and receive voice.""" + """Set up a TTS platform and call service and receive voice.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo", "language": "de"}} + config = {tts.DOMAIN: {"platform": "test", "language": "de"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -499,67 +568,67 @@ async def test_setup_component_and_test_service_with_receive_voice_german( url = await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) client = await hass_client() req = await client.get(url) - _, demo_data = demo_provider.get_tts_audio("bla", "de") - demo_data = tts.SpeechManager.write_tags( - "42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_demo.mp3", - demo_data, - demo_provider, + _, tts_data = test_provider.get_tts_audio("bla", "de") + tts_data = tts.SpeechManager.write_tags( + "42f18378fd4393d18c8dd11d03fa9563c1e54491_de_-_test.mp3", + tts_data, + test_provider, "There is someone at the door.", "de", None, ) assert req.status == HTTPStatus.OK - assert await req.read() == demo_data + assert await req.read() == tts_data async def test_setup_component_and_web_view_wrong_file( - hass: HomeAssistant, hass_client: ClientSessionGenerator + hass: HomeAssistant, hass_client: ClientSessionGenerator, mock_tts ) -> None: - """Set up the demo platform and receive wrong file from web.""" - config = {tts.DOMAIN: {"platform": "demo"}} + """Set up a TTS platform and receive wrong file from web.""" + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) client = await hass_client() - url = "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + url = "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" req = await client.get(url) assert req.status == HTTPStatus.NOT_FOUND async def test_setup_component_and_web_view_wrong_filename( - hass: HomeAssistant, hass_client: ClientSessionGenerator + hass: HomeAssistant, hass_client: ClientSessionGenerator, mock_tts ) -> None: - """Set up the demo platform and receive wrong filename from web.""" - config = {tts.DOMAIN: {"platform": "demo"}} + """Set up a TTS platform and receive wrong filename from web.""" + config = {tts.DOMAIN: {"platform": "test"}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) client = await hass_client() - url = "/api/tts_proxy/265944dsk32c1b2a621be5930510bb2cd_en_-_demo.mp3" + url = "/api/tts_proxy/265944dsk32c1b2a621be5930510bb2cd_en_-_test.mp3" req = await client.get(url) assert req.status == HTTPStatus.NOT_FOUND async def test_setup_component_test_without_cache( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up demo platform without cache.""" + """Set up a TTS platform without cache.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo", "cache": False}} + config = {tts.DOMAIN: {"platform": "test", "cache": False}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -569,24 +638,24 @@ async def test_setup_component_test_without_cache( assert len(calls) == 1 await hass.async_block_till_done() assert not ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ).is_file() async def test_setup_component_test_with_cache_call_service_without_cache( - hass: HomeAssistant, empty_cache_dir + hass: HomeAssistant, empty_cache_dir, mock_tts ) -> None: - """Set up demo platform with cache and call service without cache.""" + """Set up a TTS platform with cache and call service without cache.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - config = {tts.DOMAIN: {"platform": "demo", "cache": True}} + config = {tts.DOMAIN: {"platform": "test", "cache": True}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) await hass.services.async_call( tts.DOMAIN, - "demo_say", + "test_say", { "entity_id": "media_player.something", tts.ATTR_MESSAGE: "There is someone at the door.", @@ -597,116 +666,131 @@ async def test_setup_component_test_with_cache_call_service_without_cache( assert len(calls) == 1 await hass.async_block_till_done() assert not ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ).is_file() async def test_setup_component_test_with_cache_dir( - hass: HomeAssistant, empty_cache_dir, demo_provider + hass: HomeAssistant, empty_cache_dir, test_provider ) -> None: - """Set up demo platform with cache and call service without cache.""" + """Set up a TTS platform with cache and call service without cache.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - _, demo_data = demo_provider.get_tts_audio("bla", "en") + _, tts_data = test_provider.get_tts_audio("bla", "en") cache_file = ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ) with open(cache_file, "wb") as voice_file: - voice_file.write(demo_data) + voice_file.write(tts_data) - config = {tts.DOMAIN: {"platform": "demo", "cache": True}} + config = {tts.DOMAIN: {"platform": "test", "cache": True}} + + class MockProviderBoom(MockProvider): + def get_tts_audio( + self, message: str, language: str, options: dict[str, Any] | None = None + ) -> tts.TtsAudioType: + """Load TTS dat.""" + # This should not be called, data should be fetched from cache + raise Exception("Boom!") + + mock_integration(hass, MockModule(domain="test")) + mock_platform(hass, "test.tts", MockTTS(MockProviderBoom)) with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) - with patch( - "homeassistant.components.demo.tts.DemoProvider.get_tts_audio", - return_value=(None, None), - ): - await hass.services.async_call( - tts.DOMAIN, - "demo_say", - { - "entity_id": "media_player.something", - tts.ATTR_MESSAGE: "There is someone at the door.", - }, - blocking=True, - ) + await hass.services.async_call( + tts.DOMAIN, + "test_say", + { + "entity_id": "media_player.something", + tts.ATTR_MESSAGE: "There is someone at the door.", + }, + blocking=True, + ) assert len(calls) == 1 assert ( await get_media_source_url(hass, calls[0].data[ATTR_MEDIA_CONTENT_ID]) - == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + == "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ) async def test_setup_component_test_with_error_on_get_tts(hass: HomeAssistant) -> None: - """Set up demo platform with wrong get_tts_audio.""" - config = {tts.DOMAIN: {"platform": "demo"}} + """Set up a TTS platform with wrong get_tts_audio.""" + config = {tts.DOMAIN: {"platform": "test"}} - with assert_setup_component(1, tts.DOMAIN), patch( - "homeassistant.components.demo.tts.DemoProvider.get_tts_audio", - return_value=(None, None), - ): + class MockProviderEmpty(MockProvider): + def get_tts_audio( + self, message: str, language: str, options: dict[str, Any] | None = None + ) -> tts.TtsAudioType: + """Load TTS dat.""" + return (None, None) + + mock_integration(hass, MockModule(domain="test")) + mock_platform(hass, "test.tts", MockTTS(MockProviderEmpty)) + + with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) async def test_setup_component_load_cache_retrieve_without_mem_cache( hass: HomeAssistant, - demo_provider, + test_provider, empty_cache_dir, hass_client: ClientSessionGenerator, + mock_tts, ) -> None: """Set up component and load cache and get without mem cache.""" - _, demo_data = demo_provider.get_tts_audio("bla", "en") + _, tts_data = test_provider.get_tts_audio("bla", "en") cache_file = ( - empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + empty_cache_dir / "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" ) with open(cache_file, "wb") as voice_file: - voice_file.write(demo_data) + voice_file.write(tts_data) - config = {tts.DOMAIN: {"platform": "demo", "cache": True}} + config = {tts.DOMAIN: {"platform": "test", "cache": True}} with assert_setup_component(1, tts.DOMAIN): assert await async_setup_component(hass, tts.DOMAIN, config) client = await hass_client() - url = "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3" + url = "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3" req = await client.get(url) assert req.status == HTTPStatus.OK - assert await req.read() == demo_data + assert await req.read() == tts_data async def test_setup_component_and_web_get_url( - hass: HomeAssistant, hass_client: ClientSessionGenerator + hass: HomeAssistant, hass_client: ClientSessionGenerator, mock_tts ) -> None: - """Set up the demo platform and receive file from web.""" - config = {tts.DOMAIN: {"platform": "demo"}} + """Set up a TTS platform and receive file from web.""" + config = {tts.DOMAIN: {"platform": "test"}} await async_setup_component(hass, tts.DOMAIN, config) client = await hass_client() url = "/api/tts_get_url" - data = {"platform": "demo", "message": "There is someone at the door."} + data = {"platform": "test", "message": "There is someone at the door."} req = await client.post(url, json=data) assert req.status == HTTPStatus.OK response = await req.json() assert response == { - "url": "http://example.local:8123/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3", - "path": "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.mp3", + "url": "http://example.local:8123/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3", + "path": "/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.mp3", } async def test_setup_component_and_web_get_url_bad_config( - hass: HomeAssistant, hass_client: ClientSessionGenerator + hass: HomeAssistant, hass_client: ClientSessionGenerator, mock_tts ) -> None: - """Set up the demo platform and receive wrong file from web.""" - config = {tts.DOMAIN: {"platform": "demo"}} + """Set up a TTS platform and receive wrong file from web.""" + config = {tts.DOMAIN: {"platform": "test"}} await async_setup_component(hass, tts.DOMAIN, config) @@ -719,25 +803,25 @@ async def test_setup_component_and_web_get_url_bad_config( assert req.status == HTTPStatus.BAD_REQUEST -async def test_tags_with_wave(hass: HomeAssistant, demo_provider) -> None: - """Set up the demo platform and call service and receive voice.""" +async def test_tags_with_wave(hass: HomeAssistant, test_provider) -> None: + """Set up a TTS platform and call service and receive voice.""" # below data represents an empty wav file - demo_data = bytes.fromhex( + tts_data = bytes.fromhex( "52 49 46 46 24 00 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00" + "22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 00 00 00 00" ) tagged_data = ORIG_WRITE_TAGS( - "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_demo.wav", - demo_data, - demo_provider, + "42f18378fd4393d18c8dd11d03fa9563c1e54491_en_-_test.wav", + tts_data, + test_provider, "AI person is in front of your door.", "en", None, ) - assert tagged_data != demo_data + assert tagged_data != tts_data @pytest.mark.parametrize( @@ -781,10 +865,10 @@ def test_invalid_base_url(value) -> None: @pytest.mark.parametrize( ("engine", "language", "options", "cache", "result_engine", "result_query"), ( - (None, None, None, None, "demo", ""), - (None, "de", None, None, "demo", "language=de"), - (None, "de", {"voice": "henk"}, None, "demo", "language=de&voice=henk"), - (None, "de", None, True, "demo", "cache=true&language=de"), + (None, None, None, None, "test", ""), + (None, "de", None, None, "test", "language=de"), + (None, "de", {"voice": "henk"}, None, "test", "language=de&voice=henk"), + (None, "de", None, True, "test", "cache=true&language=de"), ), ) async def test_generate_media_source_id(