Adjust tessie tests

This commit is contained in:
Erik 2025-05-08 09:05:47 +02:00
parent 8a7123b880
commit 9a4bcd88db
7 changed files with 99 additions and 69 deletions

View File

@ -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))

View File

@ -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")

View File

@ -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

View File

@ -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"

View File

@ -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,

View File

@ -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"),

View File

@ -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)