mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[core] os.path -> Path (#10654)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
@@ -22,7 +22,7 @@ def create_cache_key() -> tuple[int, int, float, int]:
|
||||
def setup_core():
|
||||
"""Set up CORE for testing."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
CORE.config_path = str(Path(tmpdir) / "test.yaml")
|
||||
CORE.config_path = Path(tmpdir) / "test.yaml"
|
||||
yield
|
||||
CORE.reset()
|
||||
|
||||
@@ -44,7 +44,7 @@ async def dashboard_entries(mock_settings: MagicMock) -> DashboardEntries:
|
||||
|
||||
def test_dashboard_entry_path_initialization() -> None:
|
||||
"""Test DashboardEntry initializes with path correctly."""
|
||||
test_path = "/test/config/device.yaml"
|
||||
test_path = Path("/test/config/device.yaml")
|
||||
cache_key = create_cache_key()
|
||||
|
||||
entry = DashboardEntry(test_path, cache_key)
|
||||
@@ -59,21 +59,21 @@ def test_dashboard_entry_path_with_absolute_path() -> None:
|
||||
test_path = Path.cwd() / "absolute" / "path" / "to" / "config.yaml"
|
||||
cache_key = create_cache_key()
|
||||
|
||||
entry = DashboardEntry(str(test_path), cache_key)
|
||||
entry = DashboardEntry(test_path, cache_key)
|
||||
|
||||
assert entry.path == str(test_path)
|
||||
assert Path(entry.path).is_absolute()
|
||||
assert entry.path == test_path
|
||||
assert entry.path.is_absolute()
|
||||
|
||||
|
||||
def test_dashboard_entry_path_with_relative_path() -> None:
|
||||
"""Test DashboardEntry handles relative paths."""
|
||||
test_path = "configs/device.yaml"
|
||||
test_path = Path("configs/device.yaml")
|
||||
cache_key = create_cache_key()
|
||||
|
||||
entry = DashboardEntry(test_path, cache_key)
|
||||
|
||||
assert entry.path == test_path
|
||||
assert not Path(entry.path).is_absolute()
|
||||
assert not entry.path.is_absolute()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -81,12 +81,12 @@ async def test_dashboard_entries_get_by_path(
|
||||
dashboard_entries: DashboardEntries,
|
||||
) -> None:
|
||||
"""Test getting entry by path."""
|
||||
test_path = "/test/config/device.yaml"
|
||||
test_path = Path("/test/config/device.yaml")
|
||||
entry = DashboardEntry(test_path, create_cache_key())
|
||||
|
||||
dashboard_entries._entries[test_path] = entry
|
||||
dashboard_entries._entries[str(test_path)] = entry
|
||||
|
||||
result = dashboard_entries.get(test_path)
|
||||
result = dashboard_entries.get(str(test_path))
|
||||
assert result == entry
|
||||
|
||||
|
||||
@@ -104,12 +104,12 @@ async def test_dashboard_entries_path_normalization(
|
||||
dashboard_entries: DashboardEntries,
|
||||
) -> None:
|
||||
"""Test that paths are handled consistently."""
|
||||
path1 = "/test/config/device.yaml"
|
||||
path1 = Path("/test/config/device.yaml")
|
||||
|
||||
entry = DashboardEntry(path1, create_cache_key())
|
||||
dashboard_entries._entries[path1] = entry
|
||||
dashboard_entries._entries[str(path1)] = entry
|
||||
|
||||
result = dashboard_entries.get(path1)
|
||||
result = dashboard_entries.get(str(path1))
|
||||
assert result == entry
|
||||
|
||||
|
||||
@@ -118,12 +118,12 @@ async def test_dashboard_entries_path_with_spaces(
|
||||
dashboard_entries: DashboardEntries,
|
||||
) -> None:
|
||||
"""Test handling paths with spaces."""
|
||||
test_path = "/test/config/my device.yaml"
|
||||
test_path = Path("/test/config/my device.yaml")
|
||||
entry = DashboardEntry(test_path, create_cache_key())
|
||||
|
||||
dashboard_entries._entries[test_path] = entry
|
||||
dashboard_entries._entries[str(test_path)] = entry
|
||||
|
||||
result = dashboard_entries.get(test_path)
|
||||
result = dashboard_entries.get(str(test_path))
|
||||
assert result == entry
|
||||
assert result.path == test_path
|
||||
|
||||
@@ -133,18 +133,18 @@ async def test_dashboard_entries_path_with_special_chars(
|
||||
dashboard_entries: DashboardEntries,
|
||||
) -> None:
|
||||
"""Test handling paths with special characters."""
|
||||
test_path = "/test/config/device-01_test.yaml"
|
||||
test_path = Path("/test/config/device-01_test.yaml")
|
||||
entry = DashboardEntry(test_path, create_cache_key())
|
||||
|
||||
dashboard_entries._entries[test_path] = entry
|
||||
dashboard_entries._entries[str(test_path)] = entry
|
||||
|
||||
result = dashboard_entries.get(test_path)
|
||||
result = dashboard_entries.get(str(test_path))
|
||||
assert result == entry
|
||||
|
||||
|
||||
def test_dashboard_entries_windows_path() -> None:
|
||||
"""Test handling Windows-style paths."""
|
||||
test_path = r"C:\Users\test\esphome\device.yaml"
|
||||
test_path = Path(r"C:\Users\test\esphome\device.yaml")
|
||||
cache_key = create_cache_key()
|
||||
|
||||
entry = DashboardEntry(test_path, cache_key)
|
||||
@@ -157,28 +157,28 @@ async def test_dashboard_entries_path_to_cache_key_mapping(
|
||||
dashboard_entries: DashboardEntries,
|
||||
) -> None:
|
||||
"""Test internal entries storage with paths and cache keys."""
|
||||
path1 = "/test/config/device1.yaml"
|
||||
path2 = "/test/config/device2.yaml"
|
||||
path1 = Path("/test/config/device1.yaml")
|
||||
path2 = Path("/test/config/device2.yaml")
|
||||
|
||||
entry1 = DashboardEntry(path1, create_cache_key())
|
||||
entry2 = DashboardEntry(path2, (1, 1, 1.0, 1))
|
||||
|
||||
dashboard_entries._entries[path1] = entry1
|
||||
dashboard_entries._entries[path2] = entry2
|
||||
dashboard_entries._entries[str(path1)] = entry1
|
||||
dashboard_entries._entries[str(path2)] = entry2
|
||||
|
||||
assert path1 in dashboard_entries._entries
|
||||
assert path2 in dashboard_entries._entries
|
||||
assert dashboard_entries._entries[path1].cache_key == create_cache_key()
|
||||
assert dashboard_entries._entries[path2].cache_key == (1, 1, 1.0, 1)
|
||||
assert str(path1) in dashboard_entries._entries
|
||||
assert str(path2) in dashboard_entries._entries
|
||||
assert dashboard_entries._entries[str(path1)].cache_key == create_cache_key()
|
||||
assert dashboard_entries._entries[str(path2)].cache_key == (1, 1, 1.0, 1)
|
||||
|
||||
|
||||
def test_dashboard_entry_path_property() -> None:
|
||||
"""Test that path property returns expected value."""
|
||||
test_path = "/test/config/device.yaml"
|
||||
test_path = Path("/test/config/device.yaml")
|
||||
entry = DashboardEntry(test_path, create_cache_key())
|
||||
|
||||
assert entry.path == test_path
|
||||
assert isinstance(entry.path, str)
|
||||
assert isinstance(entry.path, Path)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -187,14 +187,14 @@ async def test_dashboard_entries_all_returns_entries_with_paths(
|
||||
) -> None:
|
||||
"""Test that all() returns entries with their paths intact."""
|
||||
paths = [
|
||||
"/test/config/device1.yaml",
|
||||
"/test/config/device2.yaml",
|
||||
"/test/config/subfolder/device3.yaml",
|
||||
Path("/test/config/device1.yaml"),
|
||||
Path("/test/config/device2.yaml"),
|
||||
Path("/test/config/subfolder/device3.yaml"),
|
||||
]
|
||||
|
||||
for path in paths:
|
||||
entry = DashboardEntry(path, create_cache_key())
|
||||
dashboard_entries._entries[path] = entry
|
||||
dashboard_entries._entries[str(path)] = entry
|
||||
|
||||
all_entries = dashboard_entries.async_all()
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
@@ -17,7 +16,7 @@ def dashboard_settings(tmp_path: Path) -> DashboardSettings:
|
||||
settings = DashboardSettings()
|
||||
# Resolve symlinks to ensure paths match
|
||||
resolved_dir = tmp_path.resolve()
|
||||
settings.config_dir = str(resolved_dir)
|
||||
settings.config_dir = resolved_dir
|
||||
settings.absolute_config_dir = resolved_dir
|
||||
return settings
|
||||
|
||||
@@ -26,7 +25,7 @@ def test_rel_path_simple(dashboard_settings: DashboardSettings) -> None:
|
||||
"""Test rel_path with simple relative path."""
|
||||
result = dashboard_settings.rel_path("config.yaml")
|
||||
|
||||
expected = str(Path(dashboard_settings.config_dir) / "config.yaml")
|
||||
expected = dashboard_settings.config_dir / "config.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -34,9 +33,7 @@ def test_rel_path_multiple_components(dashboard_settings: DashboardSettings) ->
|
||||
"""Test rel_path with multiple path components."""
|
||||
result = dashboard_settings.rel_path("subfolder", "device", "config.yaml")
|
||||
|
||||
expected = str(
|
||||
Path(dashboard_settings.config_dir) / "subfolder" / "device" / "config.yaml"
|
||||
)
|
||||
expected = dashboard_settings.config_dir / "subfolder" / "device" / "config.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -55,7 +52,7 @@ def test_rel_path_absolute_path_within_config(
|
||||
|
||||
internal_path.touch()
|
||||
result = dashboard_settings.rel_path("internal.yaml")
|
||||
expected = str(Path(dashboard_settings.config_dir) / "internal.yaml")
|
||||
expected = dashboard_settings.config_dir / "internal.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -80,7 +77,7 @@ def test_rel_path_with_pathlib_path(dashboard_settings: DashboardSettings) -> No
|
||||
path_obj = Path("subfolder") / "config.yaml"
|
||||
result = dashboard_settings.rel_path(path_obj)
|
||||
|
||||
expected = str(Path(dashboard_settings.config_dir) / "subfolder" / "config.yaml")
|
||||
expected = dashboard_settings.config_dir / "subfolder" / "config.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -93,9 +90,7 @@ def test_rel_path_normalizes_slashes(dashboard_settings: DashboardSettings) -> N
|
||||
assert result1 == result2
|
||||
|
||||
# Also test that the result is as expected
|
||||
expected = os.path.join(
|
||||
dashboard_settings.config_dir, "folder", "subfolder", "file.yaml"
|
||||
)
|
||||
expected = dashboard_settings.config_dir / "folder" / "subfolder" / "file.yaml"
|
||||
assert result1 == expected
|
||||
|
||||
|
||||
@@ -103,7 +98,7 @@ def test_rel_path_handles_spaces(dashboard_settings: DashboardSettings) -> None:
|
||||
"""Test rel_path handles paths with spaces."""
|
||||
result = dashboard_settings.rel_path("my folder", "my config.yaml")
|
||||
|
||||
expected = str(Path(dashboard_settings.config_dir) / "my folder" / "my config.yaml")
|
||||
expected = dashboard_settings.config_dir / "my folder" / "my config.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -111,15 +106,13 @@ def test_rel_path_handles_special_chars(dashboard_settings: DashboardSettings) -
|
||||
"""Test rel_path handles paths with special characters."""
|
||||
result = dashboard_settings.rel_path("device-01_test", "config.yaml")
|
||||
|
||||
expected = str(
|
||||
Path(dashboard_settings.config_dir) / "device-01_test" / "config.yaml"
|
||||
)
|
||||
expected = dashboard_settings.config_dir / "device-01_test" / "config.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_config_dir_as_path_property(dashboard_settings: DashboardSettings) -> None:
|
||||
"""Test that config_dir can be accessed and used with Path operations."""
|
||||
config_path = Path(dashboard_settings.config_dir)
|
||||
config_path = dashboard_settings.config_dir
|
||||
|
||||
assert config_path.exists()
|
||||
assert config_path.is_dir()
|
||||
@@ -141,7 +134,7 @@ def test_rel_path_symlink_inside_config(dashboard_settings: DashboardSettings) -
|
||||
symlink = dashboard_settings.absolute_config_dir / "link.yaml"
|
||||
symlink.symlink_to(target)
|
||||
result = dashboard_settings.rel_path("link.yaml")
|
||||
expected = str(Path(dashboard_settings.config_dir) / "link.yaml")
|
||||
expected = dashboard_settings.config_dir / "link.yaml"
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -157,12 +150,12 @@ def test_rel_path_symlink_outside_config(dashboard_settings: DashboardSettings)
|
||||
def test_rel_path_with_none_arg(dashboard_settings: DashboardSettings) -> None:
|
||||
"""Test rel_path handles None arguments gracefully."""
|
||||
result = dashboard_settings.rel_path("None")
|
||||
expected = str(Path(dashboard_settings.config_dir) / "None")
|
||||
expected = dashboard_settings.config_dir / "None"
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_rel_path_with_numeric_args(dashboard_settings: DashboardSettings) -> None:
|
||||
"""Test rel_path handles numeric arguments."""
|
||||
result = dashboard_settings.rel_path("123", "456.789")
|
||||
expected = str(Path(dashboard_settings.config_dir) / "123" / "456.789")
|
||||
expected = dashboard_settings.config_dir / "123" / "456.789"
|
||||
assert result == expected
|
||||
|
||||
@@ -49,7 +49,7 @@ def mock_trash_storage_path(tmp_path: Path) -> Generator[MagicMock]:
|
||||
"""Fixture to mock trash_storage_path."""
|
||||
trash_dir = tmp_path / "trash"
|
||||
with patch(
|
||||
"esphome.dashboard.web_server.trash_storage_path", return_value=str(trash_dir)
|
||||
"esphome.dashboard.web_server.trash_storage_path", return_value=trash_dir
|
||||
) as mock:
|
||||
yield mock
|
||||
|
||||
@@ -60,7 +60,7 @@ def mock_archive_storage_path(tmp_path: Path) -> Generator[MagicMock]:
|
||||
archive_dir = tmp_path / "archive"
|
||||
with patch(
|
||||
"esphome.dashboard.web_server.archive_storage_path",
|
||||
return_value=str(archive_dir),
|
||||
return_value=archive_dir,
|
||||
) as mock:
|
||||
yield mock
|
||||
|
||||
@@ -257,7 +257,7 @@ async def test_download_binary_handler_with_file(
|
||||
# Mock storage JSON
|
||||
mock_storage = Mock()
|
||||
mock_storage.name = "test_device"
|
||||
mock_storage.firmware_bin_path = str(firmware_file)
|
||||
mock_storage.firmware_bin_path = firmware_file
|
||||
mock_storage_json.load.return_value = mock_storage
|
||||
|
||||
response = await dashboard.fetch(
|
||||
@@ -289,7 +289,7 @@ async def test_download_binary_handler_compressed(
|
||||
# Mock storage JSON
|
||||
mock_storage = Mock()
|
||||
mock_storage.name = "test_device"
|
||||
mock_storage.firmware_bin_path = str(firmware_file)
|
||||
mock_storage.firmware_bin_path = firmware_file
|
||||
mock_storage_json.load.return_value = mock_storage
|
||||
|
||||
response = await dashboard.fetch(
|
||||
@@ -321,7 +321,7 @@ async def test_download_binary_handler_custom_download_name(
|
||||
# Mock storage JSON
|
||||
mock_storage = Mock()
|
||||
mock_storage.name = "test_device"
|
||||
mock_storage.firmware_bin_path = str(firmware_file)
|
||||
mock_storage.firmware_bin_path = firmware_file
|
||||
mock_storage_json.load.return_value = mock_storage
|
||||
|
||||
response = await dashboard.fetch(
|
||||
@@ -355,7 +355,7 @@ async def test_download_binary_handler_idedata_fallback(
|
||||
# Mock storage JSON
|
||||
mock_storage = Mock()
|
||||
mock_storage.name = "test_device"
|
||||
mock_storage.firmware_bin_path = str(firmware_file)
|
||||
mock_storage.firmware_bin_path = firmware_file
|
||||
mock_storage_json.load.return_value = mock_storage
|
||||
|
||||
# Mock idedata response
|
||||
@@ -402,7 +402,7 @@ async def test_edit_request_handler_post_existing(
|
||||
test_file.write_text("esphome:\n name: original\n")
|
||||
|
||||
# Configure the mock settings
|
||||
mock_dashboard_settings.rel_path.return_value = str(test_file)
|
||||
mock_dashboard_settings.rel_path.return_value = test_file
|
||||
mock_dashboard_settings.absolute_config_dir = test_file.parent
|
||||
|
||||
new_content = "esphome:\n name: modified\n"
|
||||
@@ -426,7 +426,7 @@ async def test_unarchive_request_handler(
|
||||
) -> None:
|
||||
"""Test the UnArchiveRequestHandler.post method."""
|
||||
# Set up an archived file
|
||||
archive_dir = Path(mock_archive_storage_path.return_value)
|
||||
archive_dir = mock_archive_storage_path.return_value
|
||||
archive_dir.mkdir(parents=True, exist_ok=True)
|
||||
archived_file = archive_dir / "archived.yaml"
|
||||
archived_file.write_text("test content")
|
||||
@@ -435,7 +435,7 @@ async def test_unarchive_request_handler(
|
||||
config_dir = tmp_path / "config"
|
||||
config_dir.mkdir(parents=True, exist_ok=True)
|
||||
destination_file = config_dir / "archived.yaml"
|
||||
mock_dashboard_settings.rel_path.return_value = str(destination_file)
|
||||
mock_dashboard_settings.rel_path.return_value = destination_file
|
||||
|
||||
response = await dashboard.fetch(
|
||||
"/unarchive?configuration=archived.yaml",
|
||||
@@ -474,7 +474,7 @@ async def test_secret_keys_handler_with_file(
|
||||
|
||||
# Configure mock to return our temp secrets file
|
||||
# Since the file actually exists, os.path.isfile will return True naturally
|
||||
mock_dashboard_settings.rel_path.return_value = str(secrets_file)
|
||||
mock_dashboard_settings.rel_path.return_value = secrets_file
|
||||
|
||||
response = await dashboard.fetch("/secret_keys", method="GET")
|
||||
assert response.code == 200
|
||||
@@ -538,8 +538,8 @@ def test_start_web_server_with_address_port(
|
||||
) -> None:
|
||||
"""Test the start_web_server function with address and port."""
|
||||
app = Mock()
|
||||
trash_dir = Path(mock_trash_storage_path.return_value)
|
||||
archive_dir = Path(mock_archive_storage_path.return_value)
|
||||
trash_dir = mock_trash_storage_path.return_value
|
||||
archive_dir = mock_archive_storage_path.return_value
|
||||
|
||||
# Create trash dir to test migration
|
||||
trash_dir.mkdir()
|
||||
@@ -643,12 +643,12 @@ async def test_archive_handler_with_build_folder(
|
||||
(build_folder / ".pioenvs").mkdir()
|
||||
|
||||
mock_dashboard_settings.config_dir = str(config_dir)
|
||||
mock_dashboard_settings.rel_path.return_value = str(test_config)
|
||||
mock_archive_storage_path.return_value = str(archive_dir)
|
||||
mock_dashboard_settings.rel_path.return_value = test_config
|
||||
mock_archive_storage_path.return_value = archive_dir
|
||||
|
||||
mock_storage = MagicMock()
|
||||
mock_storage.name = "test_device"
|
||||
mock_storage.build_path = str(build_folder)
|
||||
mock_storage.build_path = build_folder
|
||||
mock_storage_json.load.return_value = mock_storage
|
||||
|
||||
response = await dashboard.fetch(
|
||||
@@ -686,8 +686,8 @@ async def test_archive_handler_no_build_folder(
|
||||
test_config.write_text("esphome:\n name: test_device\n")
|
||||
|
||||
mock_dashboard_settings.config_dir = str(config_dir)
|
||||
mock_dashboard_settings.rel_path.return_value = str(test_config)
|
||||
mock_archive_storage_path.return_value = str(archive_dir)
|
||||
mock_dashboard_settings.rel_path.return_value = test_config
|
||||
mock_archive_storage_path.return_value = archive_dir
|
||||
|
||||
mock_storage = MagicMock()
|
||||
mock_storage.name = "test_device"
|
||||
|
||||
@@ -13,14 +13,14 @@ from esphome.dashboard import web_server
|
||||
def test_get_base_frontend_path_production() -> None:
|
||||
"""Test get_base_frontend_path in production mode."""
|
||||
mock_module = MagicMock()
|
||||
mock_module.where.return_value = "/usr/local/lib/esphome_dashboard"
|
||||
mock_module.where.return_value = Path("/usr/local/lib/esphome_dashboard")
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=True),
|
||||
patch.dict("sys.modules", {"esphome_dashboard": mock_module}),
|
||||
):
|
||||
result = web_server.get_base_frontend_path()
|
||||
assert result == "/usr/local/lib/esphome_dashboard"
|
||||
assert result == Path("/usr/local/lib/esphome_dashboard")
|
||||
mock_module.where.assert_called_once()
|
||||
|
||||
|
||||
@@ -31,13 +31,12 @@ def test_get_base_frontend_path_dev_mode() -> None:
|
||||
with patch.dict(os.environ, {"ESPHOME_DASHBOARD_DEV": test_path}):
|
||||
result = web_server.get_base_frontend_path()
|
||||
|
||||
# The function uses os.path.abspath which doesn't resolve symlinks
|
||||
# We need to match that behavior
|
||||
# The function uses Path.resolve() which resolves symlinks
|
||||
# The actual function adds "/" to the path, so we simulate that
|
||||
test_path_with_slash = test_path if test_path.endswith("/") else test_path + "/"
|
||||
expected = os.path.abspath(
|
||||
os.path.join(os.getcwd(), test_path_with_slash, "esphome_dashboard")
|
||||
)
|
||||
expected = (
|
||||
Path(os.getcwd()) / test_path_with_slash / "esphome_dashboard"
|
||||
).resolve()
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -48,8 +47,8 @@ def test_get_base_frontend_path_dev_mode_with_trailing_slash() -> None:
|
||||
with patch.dict(os.environ, {"ESPHOME_DASHBOARD_DEV": test_path}):
|
||||
result = web_server.get_base_frontend_path()
|
||||
|
||||
# The function uses os.path.abspath which doesn't resolve symlinks
|
||||
expected = os.path.abspath(str(Path.cwd() / test_path / "esphome_dashboard"))
|
||||
# The function uses Path.resolve() which resolves symlinks
|
||||
expected = (Path.cwd() / test_path / "esphome_dashboard").resolve()
|
||||
assert result == expected
|
||||
|
||||
|
||||
@@ -60,76 +59,72 @@ def test_get_base_frontend_path_dev_mode_relative_path() -> None:
|
||||
with patch.dict(os.environ, {"ESPHOME_DASHBOARD_DEV": test_path}):
|
||||
result = web_server.get_base_frontend_path()
|
||||
|
||||
# The function uses os.path.abspath which doesn't resolve symlinks
|
||||
# We need to match that behavior
|
||||
# The function uses Path.resolve() which resolves symlinks
|
||||
# The actual function adds "/" to the path, so we simulate that
|
||||
test_path_with_slash = test_path if test_path.endswith("/") else test_path + "/"
|
||||
expected = os.path.abspath(
|
||||
os.path.join(os.getcwd(), test_path_with_slash, "esphome_dashboard")
|
||||
)
|
||||
expected = (
|
||||
Path(os.getcwd()) / test_path_with_slash / "esphome_dashboard"
|
||||
).resolve()
|
||||
assert result == expected
|
||||
assert Path(result).is_absolute()
|
||||
assert result.is_absolute()
|
||||
|
||||
|
||||
def test_get_static_path_single_component() -> None:
|
||||
"""Test get_static_path with single path component."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/frontend"
|
||||
mock_base.return_value = Path("/base/frontend")
|
||||
|
||||
result = web_server.get_static_path("file.js")
|
||||
|
||||
assert result == os.path.join("/base/frontend", "static", "file.js")
|
||||
assert result == Path("/base/frontend") / "static" / "file.js"
|
||||
|
||||
|
||||
def test_get_static_path_multiple_components() -> None:
|
||||
"""Test get_static_path with multiple path components."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/frontend"
|
||||
mock_base.return_value = Path("/base/frontend")
|
||||
|
||||
result = web_server.get_static_path("js", "esphome", "index.js")
|
||||
|
||||
assert result == os.path.join(
|
||||
"/base/frontend", "static", "js", "esphome", "index.js"
|
||||
assert (
|
||||
result == Path("/base/frontend") / "static" / "js" / "esphome" / "index.js"
|
||||
)
|
||||
|
||||
|
||||
def test_get_static_path_empty_args() -> None:
|
||||
"""Test get_static_path with no arguments."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/frontend"
|
||||
mock_base.return_value = Path("/base/frontend")
|
||||
|
||||
result = web_server.get_static_path()
|
||||
|
||||
assert result == os.path.join("/base/frontend", "static")
|
||||
assert result == Path("/base/frontend") / "static"
|
||||
|
||||
|
||||
def test_get_static_path_with_pathlib_path() -> None:
|
||||
"""Test get_static_path with Path objects."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/frontend"
|
||||
mock_base.return_value = Path("/base/frontend")
|
||||
|
||||
path_obj = Path("js") / "app.js"
|
||||
result = web_server.get_static_path(str(path_obj))
|
||||
|
||||
assert result == os.path.join("/base/frontend", "static", "js", "app.js")
|
||||
assert result == Path("/base/frontend") / "static" / "js" / "app.js"
|
||||
|
||||
|
||||
def test_get_static_file_url_production() -> None:
|
||||
"""Test get_static_file_url in production mode."""
|
||||
web_server.get_static_file_url.cache_clear()
|
||||
mock_module = MagicMock()
|
||||
mock_file = MagicMock()
|
||||
mock_file.read.return_value = b"test content"
|
||||
mock_file.__enter__ = MagicMock(return_value=mock_file)
|
||||
mock_file.__exit__ = MagicMock(return_value=None)
|
||||
mock_path = MagicMock(spec=Path)
|
||||
mock_path.read_bytes.return_value = b"test content"
|
||||
|
||||
with (
|
||||
patch.dict(os.environ, {}, clear=True),
|
||||
patch.dict("sys.modules", {"esphome_dashboard": mock_module}),
|
||||
patch("esphome.dashboard.web_server.get_static_path") as mock_get_path,
|
||||
patch("esphome.dashboard.web_server.open", create=True, return_value=mock_file),
|
||||
):
|
||||
mock_get_path.return_value = "/fake/path/js/app.js"
|
||||
mock_get_path.return_value = mock_path
|
||||
result = web_server.get_static_file_url("js/app.js")
|
||||
assert result.startswith("./static/js/app.js?hash=")
|
||||
|
||||
@@ -182,26 +177,26 @@ def test_load_file_compressed_path(tmp_path: Path) -> None:
|
||||
def test_path_normalization_in_static_path() -> None:
|
||||
"""Test that paths are normalized correctly."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/frontend"
|
||||
mock_base.return_value = Path("/base/frontend")
|
||||
|
||||
# Test with separate components
|
||||
result1 = web_server.get_static_path("js", "app.js")
|
||||
result2 = web_server.get_static_path("js", "app.js")
|
||||
|
||||
assert result1 == result2
|
||||
assert result1 == os.path.join("/base/frontend", "static", "js", "app.js")
|
||||
assert result1 == Path("/base/frontend") / "static" / "js" / "app.js"
|
||||
|
||||
|
||||
def test_windows_path_handling() -> None:
|
||||
"""Test handling of Windows-style paths."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = r"C:\Program Files\esphome\frontend"
|
||||
mock_base.return_value = Path(r"C:\Program Files\esphome\frontend")
|
||||
|
||||
result = web_server.get_static_path("js", "app.js")
|
||||
|
||||
# os.path.join should handle this correctly on the platform
|
||||
expected = os.path.join(
|
||||
r"C:\Program Files\esphome\frontend", "static", "js", "app.js"
|
||||
# Path should handle this correctly on the platform
|
||||
expected = (
|
||||
Path(r"C:\Program Files\esphome\frontend") / "static" / "js" / "app.js"
|
||||
)
|
||||
assert result == expected
|
||||
|
||||
@@ -209,22 +204,20 @@ def test_windows_path_handling() -> None:
|
||||
def test_path_with_special_characters() -> None:
|
||||
"""Test paths with special characters."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/frontend"
|
||||
mock_base.return_value = Path("/base/frontend")
|
||||
|
||||
result = web_server.get_static_path("js-modules", "app_v1.0.js")
|
||||
|
||||
assert result == os.path.join(
|
||||
"/base/frontend", "static", "js-modules", "app_v1.0.js"
|
||||
assert (
|
||||
result == Path("/base/frontend") / "static" / "js-modules" / "app_v1.0.js"
|
||||
)
|
||||
|
||||
|
||||
def test_path_with_spaces() -> None:
|
||||
"""Test paths with spaces."""
|
||||
with patch("esphome.dashboard.web_server.get_base_frontend_path") as mock_base:
|
||||
mock_base.return_value = "/base/my frontend"
|
||||
mock_base.return_value = Path("/base/my frontend")
|
||||
|
||||
result = web_server.get_static_path("my js", "my app.js")
|
||||
|
||||
assert result == os.path.join(
|
||||
"/base/my frontend", "static", "my js", "my app.js"
|
||||
)
|
||||
assert result == Path("/base/my frontend") / "static" / "my js" / "my app.js"
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import py
|
||||
import pytest
|
||||
|
||||
from esphome.dashboard.util.file import write_file, write_utf8_file
|
||||
|
||||
|
||||
def test_write_utf8_file(tmp_path: Path) -> None:
|
||||
write_utf8_file(tmp_path.joinpath("foo.txt"), "foo")
|
||||
assert tmp_path.joinpath("foo.txt").read_text() == "foo"
|
||||
|
||||
with pytest.raises(OSError):
|
||||
write_utf8_file(Path("/dev/not-writable"), "bar")
|
||||
|
||||
|
||||
def test_write_file(tmp_path: Path) -> None:
|
||||
write_file(tmp_path.joinpath("foo.txt"), b"foo")
|
||||
assert tmp_path.joinpath("foo.txt").read_text() == "foo"
|
||||
|
||||
|
||||
def test_write_utf8_file_fails_at_rename(
|
||||
tmpdir: py.path.local, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test that if rename fails not not remove, we do not log the failed cleanup."""
|
||||
test_dir = tmpdir.mkdir("files")
|
||||
test_file = Path(test_dir / "test.json")
|
||||
|
||||
with (
|
||||
pytest.raises(OSError),
|
||||
patch("esphome.dashboard.util.file.os.replace", side_effect=OSError),
|
||||
):
|
||||
write_utf8_file(test_file, '{"some":"data"}', False)
|
||||
|
||||
assert not os.path.exists(test_file)
|
||||
|
||||
assert "File replacement cleanup failed" not in caplog.text
|
||||
|
||||
|
||||
def test_write_utf8_file_fails_at_rename_and_remove(
|
||||
tmpdir: py.path.local, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test that if rename and remove both fail, we log the failed cleanup."""
|
||||
test_dir = tmpdir.mkdir("files")
|
||||
test_file = Path(test_dir / "test.json")
|
||||
|
||||
with (
|
||||
pytest.raises(OSError),
|
||||
patch("esphome.dashboard.util.file.os.remove", side_effect=OSError),
|
||||
patch("esphome.dashboard.util.file.os.replace", side_effect=OSError),
|
||||
):
|
||||
write_utf8_file(test_file, '{"some":"data"}', False)
|
||||
|
||||
assert "File replacement cleanup failed" in caplog.text
|
||||
Reference in New Issue
Block a user