- Implement tag deduplication and improve tag normalization - Add toggle behavior for agenda calendar day selection - Display asset count badges on agenda calendar days - Extend agenda calendar API to support additional filters - Adjust grid controller to use semantic filter options - Update backend scanner to notify about asset updates
110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
from pathlib import Path
|
|
|
|
from mjr_am_backend.features.browser import list_filesystem_browser_entries, list_visible_subfolders
|
|
|
|
|
|
def test_list_visible_subfolders_filters_dot_hidden(tmp_path: Path) -> None:
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
(root / "visible_a").mkdir()
|
|
(root / ".hidden_a").mkdir()
|
|
|
|
res = list_visible_subfolders(root, "", "rid-1")
|
|
assert res.ok
|
|
items = res.data or []
|
|
names = {str(i.get("filename")) for i in items}
|
|
assert "visible_a" in names
|
|
assert ".hidden_a" not in names
|
|
assert all(str(i.get("kind")) == "folder" for i in items)
|
|
|
|
|
|
def test_list_visible_subfolders_rejects_traversal(tmp_path: Path) -> None:
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
outside = tmp_path / "outside"
|
|
outside.mkdir()
|
|
|
|
res = list_visible_subfolders(root, "../outside", "rid-1")
|
|
assert not res.ok
|
|
assert res.code == "INVALID_INPUT"
|
|
|
|
|
|
def test_browser_entries_roots_mode_ok() -> None:
|
|
res = list_filesystem_browser_entries("", "*", 100, 0)
|
|
assert res.ok
|
|
data = res.data or {}
|
|
assert isinstance(data.get("assets"), list)
|
|
|
|
|
|
def test_browser_entries_deep_nested_directory(tmp_path: Path) -> None:
|
|
deep_dir = tmp_path / "a" / "b" / "c" / "d"
|
|
deep_dir.mkdir(parents=True)
|
|
media = deep_dir / "image.png"
|
|
media.write_bytes(b"\x89PNG\r\n\x1a\n")
|
|
|
|
root_res = list_filesystem_browser_entries(str(tmp_path), "*", 200, 0)
|
|
assert root_res.ok
|
|
root_assets = (root_res.data.get("assets") or []) if isinstance(root_res.data, dict) else []
|
|
assert any(str(item.get("filename")) == "a" and str(item.get("kind")) == "folder" for item in root_assets)
|
|
|
|
level2_res = list_filesystem_browser_entries(str(tmp_path / "a" / "b"), "*", 200, 0)
|
|
assert level2_res.ok
|
|
level2_assets = (level2_res.data.get("assets") or []) if isinstance(level2_res.data, dict) else []
|
|
assert any(str(item.get("filename")) == "c" and str(item.get("kind")) == "folder" for item in level2_assets)
|
|
|
|
level4_res = list_filesystem_browser_entries(str(deep_dir), "*", 200, 0)
|
|
assert level4_res.ok
|
|
level4_assets = (level4_res.data.get("assets") or []) if isinstance(level4_res.data, dict) else []
|
|
assert any(str(item.get("filename")) == "image.png" for item in level4_assets)
|
|
|
|
|
|
def test_browser_entries_size_filters_apply_in_browser_mode(tmp_path: Path) -> None:
|
|
small = tmp_path / "small.png"
|
|
big = tmp_path / "big.png"
|
|
small.write_bytes(b"\x89PNG\r\n\x1a\n" + b"a" * 8)
|
|
big.write_bytes(b"\x89PNG\r\n\x1a\n" + b"b" * 4096)
|
|
|
|
res = list_filesystem_browser_entries(
|
|
str(tmp_path),
|
|
"*",
|
|
200,
|
|
0,
|
|
min_size_bytes=1024,
|
|
)
|
|
assert res.ok
|
|
assets = (res.data.get("assets") or []) if isinstance(res.data, dict) else []
|
|
names = {str(item.get("filename")) for item in assets if str(item.get("kind")) != "folder"}
|
|
assert "big.png" in names
|
|
assert "small.png" not in names
|
|
|
|
|
|
def test_browser_entries_size_max_lt_min_is_normalized(tmp_path: Path) -> None:
|
|
f = tmp_path / "x.png"
|
|
f.write_bytes(b"\x89PNG\r\n\x1a\n" + b"x" * 2048)
|
|
res = list_filesystem_browser_entries(
|
|
str(tmp_path),
|
|
"*",
|
|
200,
|
|
0,
|
|
min_size_bytes=1024,
|
|
max_size_bytes=10,
|
|
)
|
|
assert res.ok
|
|
|
|
|
|
def test_browser_entries_dimension_filters_exclude_unknown_dimensions(tmp_path: Path) -> None:
|
|
f = tmp_path / "x.png"
|
|
f.write_bytes(b"\x89PNG\r\n\x1a\n" + b"x" * 128)
|
|
|
|
res = list_filesystem_browser_entries(
|
|
str(tmp_path),
|
|
"*",
|
|
200,
|
|
0,
|
|
min_width=1,
|
|
)
|
|
assert res.ok
|
|
assets = (res.data.get("assets") or []) if isinstance(res.data, dict) else []
|
|
file_names = {str(item.get("filename")) for item in assets if str(item.get("kind")) != "folder"}
|
|
assert "x.png" not in file_names
|