From 9a4bcd88db57cd3616138c4c061afe98394b6bbc Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 8 May 2025 09:05:47 +0200 Subject: [PATCH] Adjust tessie tests --- tests/components/tts/common.py | 4 +- tests/components/tts/conftest.py | 24 ++++--- tests/components/tts/test_entity.py | 6 +- tests/components/tts/test_init.py | 83 +++++++++++++---------- tests/components/tts/test_legacy.py | 9 +-- tests/components/tts/test_media_source.py | 37 ++++++---- tests/components/tts/test_notify.py | 5 +- 7 files changed, 99 insertions(+), 69 deletions(-) diff --git a/tests/components/tts/common.py b/tests/components/tts/common.py index c21db66dfac..5f51c9b853b 100644 --- a/tests/components/tts/common.py +++ b/tests/components/tts/common.py @@ -2,7 +2,7 @@ from __future__ import annotations -from collections.abc import Generator +from collections.abc import Callable, Generator from http import HTTPStatus from pathlib import Path from typing import Any @@ -207,7 +207,7 @@ class MockTTS(MockPlatform): async def mock_setup( hass: HomeAssistant, - mock_provider: MockTTSProvider, + mock_provider: Callable[[], MockTTSProvider], ) -> None: """Set up a test provider.""" mock_integration(hass, MockModule(domain=TEST_DOMAIN)) diff --git a/tests/components/tts/conftest.py b/tests/components/tts/conftest.py index ddef3ee0c28..75e7cbe7fa5 100644 --- a/tests/components/tts/conftest.py +++ b/tests/components/tts/conftest.py @@ -3,7 +3,7 @@ From http://doc.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures """ -from collections.abc import Generator, Iterable +from collections.abc import Callable, Generator, Iterable from contextlib import ExitStack from pathlib import Path from unittest.mock import MagicMock @@ -60,22 +60,24 @@ async def internal_url_mock(hass: HomeAssistant) -> None: @pytest.fixture -async def mock_tts(hass: HomeAssistant, mock_provider) -> None: +async def mock_tts( + hass: HomeAssistant, mock_provider: Callable[[], MockTTSProvider] +) -> None: """Mock TTS.""" mock_integration(hass, MockModule(domain="test")) - mock_platform(hass, "test.tts", MockTTS(mock_provider)) + mock_platform(hass, "test.tts", MockTTS(mock_provider())) @pytest.fixture -def mock_provider() -> MockTTSProvider: +def mock_provider() -> Callable[[], MockTTSProvider]: """Test TTS provider.""" - return MockTTSProvider(DEFAULT_LANG) + return lambda: MockTTSProvider(DEFAULT_LANG) @pytest.fixture -def mock_tts_entity() -> MockTTSEntity: +def mock_tts_entity() -> Callable[[], MockTTSEntity]: """Test TTS entity.""" - return MockTTSEntity(DEFAULT_LANG) + return lambda: MockTTSEntity(DEFAULT_LANG) class TTSFlow(ConfigFlow): @@ -106,13 +108,13 @@ def config_flow_fixture( async def setup_fixture( hass: HomeAssistant, request: pytest.FixtureRequest, - mock_provider: MockTTSProvider, - mock_tts_entity: MockTTSEntity, + mock_provider: Callable[[], MockTTSProvider], + mock_tts_entity: Callable[[], MockTTSEntity], ) -> None: """Set up the test environment.""" if request.param == "mock_setup": - await mock_setup(hass, mock_provider) + await mock_setup(hass, mock_provider()) elif request.param == "mock_config_entry_setup": - await mock_config_entry_setup(hass, mock_tts_entity) + await mock_config_entry_setup(hass, mock_tts_entity()) else: raise RuntimeError("Invalid setup fixture") diff --git a/tests/components/tts/test_entity.py b/tests/components/tts/test_entity.py index d82ec6a5d2b..65311935311 100644 --- a/tests/components/tts/test_entity.py +++ b/tests/components/tts/test_entity.py @@ -1,5 +1,7 @@ """Tests for the TTS entity.""" +from collections.abc import Callable + import pytest from homeassistant.components import tts @@ -38,14 +40,14 @@ async def test_default_entity_attributes() -> None: async def test_restore_state( hass: HomeAssistant, - mock_tts_entity: MockTTSEntity, + mock_tts_entity: Callable[[], MockTTSEntity], ) -> None: """Test we restore state in the integration.""" entity_id = f"{tts.DOMAIN}.{TEST_DOMAIN}" timestamp = "2023-01-01T23:59:59+00:00" mock_restore_cache(hass, (State(entity_id, timestamp),)) - config_entry = await mock_config_entry_setup(hass, mock_tts_entity) + config_entry = await mock_config_entry_setup(hass, mock_tts_entity()) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index ea281506f3a..83446d6a8a6 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -1,6 +1,7 @@ """The tests for the TTS component.""" import asyncio +from collections.abc import Callable from http import HTTPStatus from pathlib import Path from typing import Any @@ -48,7 +49,7 @@ ORIG_WRITE_TAGS = tts.SpeechManager.write_tags async def test_config_entry_unload( hass: HomeAssistant, hass_client: ClientSessionGenerator, - mock_tts_entity: MockTTSEntity, + mock_tts_entity: Callable[[], MockTTSEntity], freezer: FrozenDateTimeFactory, ) -> None: """Test we can unload config entry.""" @@ -56,7 +57,7 @@ async def test_config_entry_unload( state = hass.states.get(entity_id) assert state is None - config_entry = await mock_config_entry_setup(hass, mock_tts_entity) + config_entry = await mock_config_entry_setup(hass, mock_tts_entity()) assert config_entry.state is ConfigEntryState.LOADED state = hass.states.get(entity_id) assert state is not None @@ -178,7 +179,7 @@ async def test_service( @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MockTTSProvider("de_DE"), MockTTSEntity("de_DE"))], + [(lambda: MockTTSProvider("de_DE"), lambda: MockTTSEntity("de_DE"))], ) @pytest.mark.parametrize( ("setup", "tts_service", "service_data", "expected_url_suffix"), @@ -242,7 +243,7 @@ async def test_service_default_language( @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MockTTSProvider("en_US"), MockTTSEntity("en_US"))], + [(lambda: MockTTSProvider("en_US"), lambda: MockTTSEntity("en_US"))], ) @pytest.mark.parametrize( ("setup", "tts_service", "service_data", "expected_url_suffix"), @@ -498,7 +499,12 @@ class MockEntityWithDefaults(MockTTSEntity): @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MockProviderWithDefaults(DEFAULT_LANG), MockEntityWithDefaults(DEFAULT_LANG))], + [ + ( + lambda: MockProviderWithDefaults(DEFAULT_LANG), + lambda: MockEntityWithDefaults(DEFAULT_LANG), + ) + ], ) @pytest.mark.parametrize( ("setup", "tts_service", "service_data", "expected_url_suffix"), @@ -567,7 +573,12 @@ async def test_service_default_options( @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MockProviderWithDefaults(DEFAULT_LANG), MockEntityWithDefaults(DEFAULT_LANG))], + [ + ( + lambda: MockProviderWithDefaults(DEFAULT_LANG), + lambda: MockEntityWithDefaults(DEFAULT_LANG), + ) + ], ) @pytest.mark.parametrize( ("setup", "tts_service", "service_data", "expected_url_suffix"), @@ -830,7 +841,7 @@ async def test_service_receive_voice( @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MockTTSProvider("de_DE"), MockTTSEntity("de_DE"))], + [(lambda: MockTTSProvider("de_DE"), lambda: MockTTSEntity("de_DE"))], ) @pytest.mark.parametrize( ("setup", "tts_service", "service_data", "expected_url_suffix"), @@ -1013,11 +1024,11 @@ class MockEntityBoom(MockTTSEntity): raise Exception("Boom!") # noqa: TRY002 -@pytest.mark.parametrize("mock_provider", [MockProviderBoom(DEFAULT_LANG)]) +@pytest.mark.parametrize("mock_provider", [lambda: MockProviderBoom(DEFAULT_LANG)]) async def test_setup_legacy_cache_dir( hass: HomeAssistant, mock_tts_cache_dir: Path, - mock_provider: MockTTSProvider, + mock_provider: Callable[[], MockTTSProvider], ) -> None: """Set up a TTS platform with cache and call service without cache.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) @@ -1028,7 +1039,7 @@ async def test_setup_legacy_cache_dir( ) await hass.async_add_executor_job(Path(cache_file).write_bytes, tts_data) - await mock_setup(hass, mock_provider) + await mock_setup(hass, mock_provider()) await hass.services.async_call( tts.DOMAIN, @@ -1051,11 +1062,11 @@ async def test_setup_legacy_cache_dir( await hass.async_block_till_done() -@pytest.mark.parametrize("mock_tts_entity", [MockEntityBoom(DEFAULT_LANG)]) +@pytest.mark.parametrize("mock_tts_entity", [lambda: MockEntityBoom(DEFAULT_LANG)]) async def test_setup_cache_dir( hass: HomeAssistant, mock_tts_cache_dir: Path, - mock_tts_entity: MockTTSEntity, + mock_tts_entity: Callable[[], MockTTSEntity], ) -> None: """Set up a TTS platform with cache and call service without cache.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) @@ -1066,7 +1077,7 @@ async def test_setup_cache_dir( ) await hass.async_add_executor_job(Path(cache_file).write_bytes, tts_data) - await mock_config_entry_setup(hass, mock_tts_entity) + await mock_config_entry_setup(hass, mock_tts_entity()) await hass.services.async_call( tts.DOMAIN, @@ -1111,7 +1122,7 @@ class MockEntityEmpty(MockTTSEntity): @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MockProviderEmpty(DEFAULT_LANG), MockEntityEmpty(DEFAULT_LANG))], + [(lambda: MockProviderEmpty(DEFAULT_LANG), lambda: MockEntityEmpty(DEFAULT_LANG))], ) @pytest.mark.parametrize( ("setup", "tts_service", "service_data"), @@ -1161,7 +1172,7 @@ async def test_service_get_tts_error( async def test_legacy_cannot_retrieve_without_token( hass: HomeAssistant, - mock_provider: MockTTSProvider, + mock_provider: Callable[[], MockTTSProvider], mock_tts_cache_dir: Path, hass_client: ClientSessionGenerator, ) -> None: @@ -1172,7 +1183,7 @@ async def test_legacy_cannot_retrieve_without_token( ) await hass.async_add_executor_job(Path(cache_file).write_bytes, tts_data) - await mock_setup(hass, mock_provider) + await mock_setup(hass, mock_provider()) client = await hass_client() @@ -1184,7 +1195,7 @@ async def test_legacy_cannot_retrieve_without_token( async def test_cannot_retrieve_without_token( hass: HomeAssistant, - mock_tts_entity: MockTTSEntity, + mock_tts_entity: Callable[[], MockTTSEntity], mock_tts_cache_dir: Path, hass_client: ClientSessionGenerator, ) -> None: @@ -1195,7 +1206,7 @@ async def test_cannot_retrieve_without_token( ) await hass.async_add_executor_job(Path(cache_file).write_bytes, tts_data) - await mock_config_entry_setup(hass, mock_tts_entity) + await mock_config_entry_setup(hass, mock_tts_entity()) client = await hass_client() @@ -1651,7 +1662,7 @@ async def test_ws_list_engines( async def test_ws_list_engines_deprecated( hass: HomeAssistant, hass_ws_client: WebSocketGenerator, - mock_tts_entity: MockTTSEntity, + mock_tts_entity: Callable[[], MockTTSEntity], ) -> None: """Test listing tts engines. @@ -1668,7 +1679,7 @@ async def test_ws_list_engines_deprecated( await async_setup_component( hass, "tts", {"tts": [{"platform": "test"}, {"platform": "test_2"}]} ) - await mock_config_entry_setup(hass, mock_tts_entity) + await mock_config_entry_setup(hass, mock_tts_entity()) client = await hass_ws_client() @@ -1822,18 +1833,19 @@ async def test_async_convert_audio_error(hass: HomeAssistant) -> None: async def test_default_engine_prefer_entity( hass: HomeAssistant, - mock_tts_entity: MockTTSEntity, - mock_provider: MockTTSProvider, + mock_tts_entity: Callable[[], MockTTSEntity], + mock_provider: Callable[[], MockTTSProvider], ) -> None: """Test async_default_engine. In this tests there's an entity and a legacy provider. The test asserts async_default_engine returns the entity. """ - mock_tts_entity._attr_name = "New test" + tts_entity = mock_tts_entity() + tts_entity._attr_name = "New test" - await mock_setup(hass, mock_provider) - await mock_config_entry_setup(hass, mock_tts_entity) + await mock_setup(hass, mock_provider()) + await mock_config_entry_setup(hass, tts_entity) await hass.async_block_till_done() entity_engine = tts.async_resolve_engine(hass, "tts.new_test") @@ -1854,7 +1866,7 @@ async def test_default_engine_prefer_entity( ) async def test_default_engine_prefer_cloud_entity( hass: HomeAssistant, - mock_provider: MockTTSProvider, + mock_provider: Callable[[], MockTTSProvider], config_flow_test_domains: str, ) -> None: """Test async_default_engine. @@ -1863,7 +1875,7 @@ async def test_default_engine_prefer_cloud_entity( and a legacy provider. The test asserts async_default_engine returns the entity from domain cloud. """ - await mock_setup(hass, mock_provider) + await mock_setup(hass, mock_provider()) for domain in config_flow_test_domains: entity = MockTTSEntity(DEFAULT_LANG) entity._attr_name = f"{domain} TTS entity" @@ -1878,13 +1890,16 @@ async def test_default_engine_prefer_cloud_entity( assert tts.async_default_engine(hass) == "tts.cloud_tts_entity" -async def test_stream(hass: HomeAssistant, mock_tts_entity: MockTTSEntity) -> None: +async def test_stream( + hass: HomeAssistant, mock_tts_entity: Callable[[], MockTTSEntity] +) -> None: """Test creating streams.""" - await mock_config_entry_setup(hass, mock_tts_entity) + tts_entity = mock_tts_entity() + await mock_config_entry_setup(hass, tts_entity) - stream = tts.async_create_stream(hass, mock_tts_entity.entity_id) - assert stream.language == mock_tts_entity.default_language - assert stream.options == (mock_tts_entity.default_options or {}) + stream = tts.async_create_stream(hass, tts_entity.entity_id) + assert stream.language == tts_entity.default_language + assert stream.options == (tts_entity.default_options or {}) assert tts.async_get_stream(hass, stream.token) is stream stream.async_set_message("beer") result_data = b"".join([chunk async for chunk in stream.async_stream_result()]) @@ -1904,7 +1919,7 @@ async def test_stream(hass: HomeAssistant, mock_tts_entity: MockTTSEntity) -> No data_gen=gen_data(), ) - mock_tts_entity.async_stream_tts_audio = async_stream_tts_audio + tts_entity.async_stream_tts_audio = async_stream_tts_audio async def stream_message(): """Mock stream message.""" @@ -1912,7 +1927,7 @@ async def test_stream(hass: HomeAssistant, mock_tts_entity: MockTTSEntity) -> No yield "ll" yield "o" - stream = tts.async_create_stream(hass, mock_tts_entity.entity_id) + stream = tts.async_create_stream(hass, tts_entity.entity_id) stream.async_set_message_stream(stream_message()) result_data = b"".join([chunk async for chunk in stream.async_stream_result()]) assert result_data == b"hello" diff --git a/tests/components/tts/test_legacy.py b/tests/components/tts/test_legacy.py index 22e8ac35f16..583eb8d76ae 100644 --- a/tests/components/tts/test_legacy.py +++ b/tests/components/tts/test_legacy.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import Callable from pathlib import Path import pytest @@ -77,7 +78,7 @@ async def test_invalid_platform( async def test_platform_setup_without_provider( hass: HomeAssistant, caplog: pytest.LogCaptureFixture, - mock_provider: MockTTSProvider, + mock_provider: Callable[[], MockTTSProvider], ) -> None: """Test platform setup without provider returned.""" @@ -94,7 +95,7 @@ async def test_platform_setup_without_provider( return None mock_integration(hass, MockModule(domain="bad_tts")) - mock_platform(hass, "bad_tts.tts", BadPlatform(mock_provider)) + mock_platform(hass, "bad_tts.tts", BadPlatform(mock_provider())) await async_load_platform( hass, @@ -111,7 +112,7 @@ async def test_platform_setup_without_provider( async def test_platform_setup_with_error( hass: HomeAssistant, caplog: pytest.LogCaptureFixture, - mock_provider: MockTTSProvider, + mock_provider: Callable[[], MockTTSProvider], ) -> None: """Test platform setup with an error during setup.""" @@ -128,7 +129,7 @@ async def test_platform_setup_with_error( raise Exception("Setup error") # noqa: TRY002 mock_integration(hass, MockModule(domain="bad_tts")) - mock_platform(hass, "bad_tts.tts", BadPlatform(mock_provider)) + mock_platform(hass, "bad_tts.tts", BadPlatform(mock_provider())) await async_load_platform( hass, diff --git a/tests/components/tts/test_media_source.py b/tests/components/tts/test_media_source.py index eb4b09cab5b..7f0257bf051 100644 --- a/tests/components/tts/test_media_source.py +++ b/tests/components/tts/test_media_source.py @@ -1,5 +1,6 @@ """Tests for TTS media source.""" +from collections.abc import Callable from http import HTTPStatus import re from unittest.mock import MagicMock @@ -47,7 +48,7 @@ async def setup_media_source(hass: HomeAssistant) -> None: @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MSProvider(DEFAULT_LANG), MSEntity(DEFAULT_LANG))], + [(lambda: MSProvider(DEFAULT_LANG), lambda: MSEntity(DEFAULT_LANG))], ) @pytest.mark.parametrize( "setup", @@ -101,24 +102,28 @@ async def test_browsing(hass: HomeAssistant, setup: str) -> None: @pytest.mark.parametrize( ("mock_provider", "extra_options"), [ - (MSProvider(DEFAULT_LANG), "&tts_options=%7B%22voice%22%3A%22Paulus%22%7D"), - (MSProvider(DEFAULT_LANG), "&voice=Paulus"), + ( + lambda: MSProvider(DEFAULT_LANG), + "&tts_options=%7B%22voice%22%3A%22Paulus%22%7D", + ), + (lambda: MSProvider(DEFAULT_LANG), "&voice=Paulus"), ], ) async def test_legacy_resolving( hass: HomeAssistant, hass_client: ClientSessionGenerator, - mock_provider: MSProvider, + mock_provider: Callable[[], MSProvider], extra_options: str, ) -> None: """Test resolving legacy provider.""" - await mock_setup(hass, mock_provider) - mock_get_tts_audio = mock_provider.get_tts_audio + provider = mock_provider() + await mock_setup(hass, provider) + mock_get_tts_audio = provider.get_tts_audio - mock_provider.has_entity = True + provider.has_entity = True root = await media_source.async_browse_media(hass, "media-source://tts") assert len(root.children) == 0 - mock_provider.has_entity = False + provider.has_entity = False root = await media_source.async_browse_media(hass, "media-source://tts") assert len(root.children) == 1 @@ -155,19 +160,23 @@ async def test_legacy_resolving( @pytest.mark.parametrize( ("mock_tts_entity", "extra_options"), [ - (MSEntity(DEFAULT_LANG), "&tts_options=%7B%22voice%22%3A%22Paulus%22%7D"), - (MSEntity(DEFAULT_LANG), "&voice=Paulus"), + ( + lambda: MSEntity(DEFAULT_LANG), + "&tts_options=%7B%22voice%22%3A%22Paulus%22%7D", + ), + (lambda: MSEntity(DEFAULT_LANG), "&voice=Paulus"), ], ) async def test_resolving( hass: HomeAssistant, hass_client: ClientSessionGenerator, - mock_tts_entity: MSEntity, + mock_tts_entity: Callable[[], MSEntity], extra_options: str, ) -> None: """Test resolving entity.""" - await mock_config_entry_setup(hass, mock_tts_entity) - mock_get_tts_audio = mock_tts_entity.get_tts_audio + tts_entity = mock_tts_entity() + await mock_config_entry_setup(hass, tts_entity) + mock_get_tts_audio = tts_entity.get_tts_audio mock_get_tts_audio.reset_mock() media_id = "media-source://tts/tts.test?message=Hello%20World" @@ -201,7 +210,7 @@ async def test_resolving( @pytest.mark.parametrize( ("mock_provider", "mock_tts_entity"), - [(MSProvider(DEFAULT_LANG), MSEntity(DEFAULT_LANG))], + [(lambda: MSProvider(DEFAULT_LANG), lambda: MSEntity(DEFAULT_LANG))], ) @pytest.mark.parametrize( ("setup", "engine"), diff --git a/tests/components/tts/test_notify.py b/tests/components/tts/test_notify.py index 00cdae2934f..e63f25a6928 100644 --- a/tests/components/tts/test_notify.py +++ b/tests/components/tts/test_notify.py @@ -1,5 +1,6 @@ """The tests for the TTS component.""" +from collections.abc import Callable from unittest.mock import patch import pytest @@ -127,7 +128,7 @@ async def test_setup_legacy_service(hass: HomeAssistant) -> None: async def test_setup_service( - hass: HomeAssistant, mock_tts_entity: MockTTSEntity + hass: HomeAssistant, mock_tts_entity: Callable[[], MockTTSEntity] ) -> None: """Set up platform and call service.""" calls = async_mock_service(hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) @@ -142,7 +143,7 @@ async def test_setup_service( }, } - await mock_config_entry_setup(hass, mock_tts_entity) + await mock_config_entry_setup(hass, mock_tts_entity()) with assert_setup_component(1, notify.DOMAIN): assert await async_setup_component(hass, notify.DOMAIN, config)