diff --git a/tests/test_style_loader.py b/tests/test_style_loader.py index 39a622d..4f158d9 100644 --- a/tests/test_style_loader.py +++ b/tests/test_style_loader.py @@ -4,120 +4,8 @@ from unittest.mock import MagicMock, patch import pytest from aiohttp import web -from src.nodes.style_loader import ( - STYLE_TEMPLATE, - _apply_loras, - _load_style, - _safe_relative_path, - _scan_style_files, -) - -# --- Fixtures --- - - -@pytest.fixture -def styles_dir(tmp_path): - return tmp_path - - -@pytest.fixture -def style_file(tmp_path): - def _make(data: dict, name: str = "test.json", subdir: str | None = None): - target = tmp_path / subdir if subdir else tmp_path - target.mkdir(parents=True, exist_ok=True) - path = target / name - path.write_text(json.dumps(data), encoding="utf-8") - return str(tmp_path) - - return _make - - -# --- _safe_relative_path --- - - -def test_safe_relative_path_simple(): - assert _safe_relative_path("anime.json") == "anime.json" - - -def test_safe_relative_path_subdir(): - result = _safe_relative_path("anime/illustrious.json") - assert result == os.path.normpath("anime/illustrious.json") - - -def test_safe_relative_path_traversal(): - assert _safe_relative_path("../../etc/passwd") is None - - -def test_safe_relative_path_absolute(): - assert _safe_relative_path("/etc/passwd") is None - - -def test_safe_relative_path_dotdot_middle(): - result = _safe_relative_path("anime/../../../etc/passwd") - assert result is None - - -# --- _scan_style_files --- - - -def test_scan_empty_dir(styles_dir): - result = _scan_style_files(str(styles_dir)) - assert result == ["-- no styles found --"] - - -def test_scan_single_file(styles_dir): - (styles_dir / "anime.json").write_text("{}") - result = _scan_style_files(str(styles_dir)) - assert result == ["anime.json"] - - -def test_scan_subdir(styles_dir): - sub = styles_dir / "realistic" - sub.mkdir() - (sub / "photon.json").write_text("{}") - result = _scan_style_files(str(styles_dir)) - assert result == ["realistic/photon.json"] - - -def test_scan_ignores_non_json(styles_dir): - (styles_dir / "readme.txt").write_text("hello") - (styles_dir / "style.json").write_text("{}") - result = _scan_style_files(str(styles_dir)) - assert result == ["style.json"] - - -def test_scan_sorted(styles_dir): - for name in ["zebra.json", "alpha.json", "middle.json"]: - (styles_dir / name).write_text("{}") - result = _scan_style_files(str(styles_dir)) - assert result == ["alpha.json", "middle.json", "zebra.json"] - - -# --- _load_style --- - - -def test_load_style_basic(style_file): - data = {"checkpoint": "model.safetensors", "cfg": 7.5} - base_dir = style_file(data) - with patch("src.nodes.style_loader.STYLES_DIR", base_dir): - result = _load_style("test.json") - assert result["checkpoint"] == "model.safetensors" - assert result["cfg"] == 7.5 - - -def test_load_style_not_found(tmp_path): - with patch("src.nodes.style_loader.STYLES_DIR", str(tmp_path)): - with pytest.raises(FileNotFoundError): - _load_style("missing.json") - - -def test_load_style_subdir(style_file): - data = {"checkpoint": "model.safetensors"} - base_dir = style_file(data, name="photon.json", subdir="realistic") - with patch("src.nodes.style_loader.STYLES_DIR", base_dir): - result = _load_style("realistic/photon.json") - assert result["checkpoint"] == "model.safetensors" - +from src.nodes.style_loader import STYLE_TEMPLATE, _apply_loras +from src.utils_loader import safe_relative_path # --- _apply_loras --- @@ -240,7 +128,7 @@ def app(tmp_path): body = await request.json() file = body.get("file", "") content = body.get("content", "") - rel = _safe_relative_path(file) + rel = safe_relative_path(file) if not rel: return web.json_response({"error": "Invalid file path."}, status=400) try: @@ -260,7 +148,7 @@ def app(tmp_path): return web.json_response({"error": "File name is required."}, status=400) if not file.endswith(".json"): file += ".json" - rel = _safe_relative_path(file) + rel = safe_relative_path(file) if not rel: return web.json_response({"error": "Invalid file path."}, status=400) path = os.path.join(str(tmp_path), rel) @@ -276,7 +164,7 @@ def app(tmp_path): async def load_handler(request): file = request.rel_url.query.get("file", "") - rel = _safe_relative_path(file) + rel = safe_relative_path(file) if not rel: return web.json_response({"error": "Invalid file path."}, status=400) path = os.path.join(str(tmp_path), rel) @@ -290,7 +178,7 @@ def app(tmp_path): async def delete_handler(request): body = await request.json() file = body.get("file", "") - rel = _safe_relative_path(file) + rel = safe_relative_path(file) if not rel: return web.json_response({"error": "Invalid file path."}, status=400) path = os.path.join(str(tmp_path), rel) diff --git a/tests/test_utils_loader.py b/tests/test_utils_loader.py new file mode 100644 index 0000000..e52a3e7 --- /dev/null +++ b/tests/test_utils_loader.py @@ -0,0 +1,152 @@ +import json +import os +from unittest.mock import patch + +import pytest +from src.utils_loader import ( + delete_file, + load_json_file, + safe_relative_path, + save_json_file, + scan_files, +) + +# --- Fixtures --- + + +@pytest.fixture +def styles_dir(tmp_path): + return tmp_path + + +@pytest.fixture +def style_file(tmp_path): + def _make(data: dict, name: str = "test.json", subdir: str | None = None): + target = tmp_path / subdir if subdir else tmp_path + target.mkdir(parents=True, exist_ok=True) + path = target / name + path.write_text(json.dumps(data), encoding="utf-8") + return str(tmp_path) + + return _make + + +# --- safe_relative_path --- + + +def test_safe_relative_path_simple(): + assert safe_relative_path("anime.json") == "anime.json" + + +def test_safe_relative_path_subdir(): + result = safe_relative_path("anime/illustrious.json") + assert result == os.path.normpath("anime/illustrious.json") + + +def test_safe_relative_path_traversal(): + assert safe_relative_path("../../etc/passwd") is None + + +def test_safe_relative_path_absolute(): + assert safe_relative_path("/etc/passwd") is None + + +def test_safe_relative_path_dotdot_middle(): + result = safe_relative_path("anime/../../../etc/passwd") + assert result is None + + +# --- scan_files --- + + +def test_scan_empty_dir(styles_dir): + result = scan_files(str(styles_dir)) + assert result == ["-- no files found --"] + + +def test_scan_single_file(styles_dir): + (styles_dir / "anime.json").write_text("{}") + result = scan_files(str(styles_dir)) + assert result == ["anime.json"] + + +def test_scan_subdir(styles_dir): + sub = styles_dir / "realistic" + sub.mkdir() + (sub / "photon.json").write_text("{}") + result = scan_files(str(styles_dir)) + assert result == ["realistic/photon.json"] + + +def test_scan_ignores_non_json(styles_dir): + (styles_dir / "readme.txt").write_text("hello") + (styles_dir / "style.json").write_text("{}") + result = scan_files(str(styles_dir)) + assert result == ["style.json"] + + +def test_scan_sorted(styles_dir): + for name in ["zebra.json", "alpha.json", "middle.json"]: + (styles_dir / name).write_text("{}") + result = scan_files(str(styles_dir)) + assert result == ["alpha.json", "middle.json", "zebra.json"] + + +# --- load_json_file --- + + +def test_load_style_basic(style_file): + data = {"checkpoint": "model.safetensors", "cfg": 7.5} + base_dir = style_file(data) + with patch("src.nodes.style_loader.STYLES_DIR", base_dir): + result = load_json_file(base_dir, "test.json") + assert result["checkpoint"] == "model.safetensors" + assert result["cfg"] == 7.5 + + +def test_load_style_not_found(tmp_path): + with patch("src.nodes.style_loader.STYLES_DIR", str(tmp_path)): + with pytest.raises(FileNotFoundError): + load_json_file(str(tmp_path), "missing.json") + + +def test_load_style_subdir(style_file): + data = {"checkpoint": "model.safetensors"} + base_dir = style_file(data, name="photon.json", subdir="realistic") + with patch("src.nodes.style_loader.STYLES_DIR", base_dir): + result = load_json_file(base_dir, "realistic/photon.json") + assert result["checkpoint"] == "model.safetensors" + + +# --- save_json_file --- + + +def test_save_json_file_creates_file(tmp_path): + save_json_file(str(tmp_path), "test.json", '{"key": "value"}') + assert (tmp_path / "test.json").exists() + assert json.loads((tmp_path / "test.json").read_text()) == {"key": "value"} + + +def test_save_json_file_creates_subdir(tmp_path): + save_json_file(str(tmp_path), "sub/test.json", '{"key": "value"}') + assert (tmp_path / "sub" / "test.json").exists() + + +def test_save_json_file_overwrites(tmp_path): + (tmp_path / "test.json").write_text('{"old": true}') + save_json_file(str(tmp_path), "test.json", '{"new": true}') + assert json.loads((tmp_path / "test.json").read_text()) == {"new": True} + + +# --- delete_file --- + + +def test_delete_file_removes(tmp_path): + (tmp_path / "test.json").write_text("{}") + delete_file(str(tmp_path), "test.json") + assert not (tmp_path / "test.json").exists() + + +def test_delete_file_not_found(tmp_path): + with pytest.raises(FileNotFoundError): + delete_file(str(tmp_path), "missing.json")