Merge remote-tracking branch 'upstream/dev' into integration

This commit is contained in:
J. Nick Koston
2026-04-22 22:32:06 -05:00
8 changed files with 108 additions and 10 deletions
+66 -1
View File
@@ -1,6 +1,11 @@
"""Tests for time component cron expression parsing."""
from esphome.components.time import _parse_cron_part
import errno
from unittest.mock import MagicMock, patch
import pytest
from esphome.components.time import _load_tzdata, _parse_cron_part, validate_tz
def test_star_slash_seconds() -> None:
@@ -78,3 +83,63 @@ def test_range() -> None:
def test_single_value() -> None:
assert _parse_cron_part("30", 0, 59, {}) == {30}
def _mock_resources_with_error(error: Exception) -> MagicMock:
"""Return a mock of importlib.resources.files where read_bytes raises error."""
leaf = MagicMock()
leaf.read_bytes.side_effect = error
package = MagicMock()
package.__truediv__.return_value = leaf
return MagicMock(return_value=package)
def test_load_tzdata_returns_none_on_windows_einval() -> None:
"""On Windows, opening a tzdata path with NTFS-illegal chars raises OSError(EINVAL).
Regression test for crash when the system TZ resolves to a POSIX string like
"<+08>-8" (Asia/Shanghai, IST, etc.) and is fed back into _load_tzdata by
validate_tz to check whether it is also a valid IANA key.
"""
err = OSError(errno.EINVAL, "Invalid argument")
with patch(
"esphome.components.time.resources.files",
_mock_resources_with_error(err),
):
assert _load_tzdata("<+08>-8") is None
def test_load_tzdata_propagates_unexpected_oserror() -> None:
"""Unrelated OSErrors (e.g. PermissionError) must not be swallowed."""
with (
patch(
"esphome.components.time.resources.files",
_mock_resources_with_error(
PermissionError(errno.EACCES, "Permission denied")
),
),
pytest.raises(PermissionError),
):
_load_tzdata("Some/Zone")
def test_load_tzdata_returns_none_on_file_not_found() -> None:
"""Existing behavior: missing tz file returns None rather than raising."""
with patch(
"esphome.components.time.resources.files",
_mock_resources_with_error(FileNotFoundError()),
):
assert _load_tzdata("Not/A/Zone") is None
def test_validate_tz_accepts_posix_string_when_read_bytes_raises_einval() -> None:
"""validate_tz must not crash when _load_tzdata hits the Windows EINVAL path.
Simulates the Windows case where the auto-detected POSIX TZ string is fed
back through _load_tzdata and the underlying read_bytes raises errno 22.
"""
with patch(
"esphome.components.time.resources.files",
_mock_resources_with_error(OSError(errno.EINVAL, "Invalid argument")),
):
assert validate_tz("<+08>-8") == "<+08>-8"