mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-03-04 16:57:31 +08:00
list_files_recursively now uses followlinks=True so symlinked directories under input/ and output/ roots are traversed, matching the existing behavior of folder_paths.recursive_search for models. Tracks (st_dev, st_ino) pairs of visited directories to detect and break circular symlink loops safely. Amp-Thread-ID: https://ampcode.com/threads/T-019c9220-21b8-7678-b428-9215ff1bb011 Co-authored-by: Amp <amp@ampcode.com>
122 lines
3.8 KiB
Python
122 lines
3.8 KiB
Python
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
from app.assets.services.file_utils import is_visible, list_files_recursively
|
|
|
|
|
|
class TestIsVisible:
|
|
def test_visible_file(self):
|
|
assert is_visible("file.txt") is True
|
|
|
|
def test_hidden_file(self):
|
|
assert is_visible(".hidden") is False
|
|
|
|
def test_hidden_directory(self):
|
|
assert is_visible(".git") is False
|
|
|
|
def test_visible_directory(self):
|
|
assert is_visible("src") is True
|
|
|
|
def test_dotdot_is_hidden(self):
|
|
assert is_visible("..") is False
|
|
|
|
def test_dot_is_hidden(self):
|
|
assert is_visible(".") is False
|
|
|
|
|
|
class TestListFilesRecursively:
|
|
def test_skips_hidden_files(self, tmp_path):
|
|
(tmp_path / "visible.txt").write_text("a")
|
|
(tmp_path / ".hidden").write_text("b")
|
|
|
|
result = list_files_recursively(str(tmp_path))
|
|
|
|
assert len(result) == 1
|
|
assert result[0].endswith("visible.txt")
|
|
|
|
def test_skips_hidden_directories(self, tmp_path):
|
|
hidden_dir = tmp_path / ".hidden_dir"
|
|
hidden_dir.mkdir()
|
|
(hidden_dir / "file.txt").write_text("a")
|
|
|
|
visible_dir = tmp_path / "visible_dir"
|
|
visible_dir.mkdir()
|
|
(visible_dir / "file.txt").write_text("b")
|
|
|
|
result = list_files_recursively(str(tmp_path))
|
|
|
|
assert len(result) == 1
|
|
assert "visible_dir" in result[0]
|
|
assert ".hidden_dir" not in result[0]
|
|
|
|
def test_empty_directory(self, tmp_path):
|
|
result = list_files_recursively(str(tmp_path))
|
|
assert result == []
|
|
|
|
def test_nonexistent_directory(self, tmp_path):
|
|
result = list_files_recursively(str(tmp_path / "nonexistent"))
|
|
assert result == []
|
|
|
|
@pytest.mark.skipif(sys.platform == "win32", reason="symlinks need privileges on Windows")
|
|
def test_follows_symlinked_directories(self, tmp_path):
|
|
target = tmp_path / "real_dir"
|
|
target.mkdir()
|
|
(target / "model.safetensors").write_text("data")
|
|
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
(root / "link").symlink_to(target)
|
|
|
|
result = list_files_recursively(str(root))
|
|
|
|
assert len(result) == 1
|
|
assert result[0].endswith("model.safetensors")
|
|
assert "link" in result[0]
|
|
|
|
@pytest.mark.skipif(sys.platform == "win32", reason="symlinks need privileges on Windows")
|
|
def test_follows_symlinked_files(self, tmp_path):
|
|
real_file = tmp_path / "real.txt"
|
|
real_file.write_text("content")
|
|
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
(root / "link.txt").symlink_to(real_file)
|
|
|
|
result = list_files_recursively(str(root))
|
|
|
|
assert len(result) == 1
|
|
assert result[0].endswith("link.txt")
|
|
|
|
@pytest.mark.skipif(sys.platform == "win32", reason="symlinks need privileges on Windows")
|
|
def test_circular_symlinks_do_not_loop(self, tmp_path):
|
|
dir_a = tmp_path / "a"
|
|
dir_a.mkdir()
|
|
(dir_a / "file.txt").write_text("a")
|
|
# a/b -> a (circular)
|
|
(dir_a / "b").symlink_to(dir_a)
|
|
|
|
result = list_files_recursively(str(dir_a))
|
|
|
|
assert len(result) == 1
|
|
assert result[0].endswith("file.txt")
|
|
|
|
@pytest.mark.skipif(sys.platform == "win32", reason="symlinks need privileges on Windows")
|
|
def test_mutual_circular_symlinks(self, tmp_path):
|
|
dir_a = tmp_path / "a"
|
|
dir_b = tmp_path / "b"
|
|
dir_a.mkdir()
|
|
dir_b.mkdir()
|
|
(dir_a / "file_a.txt").write_text("a")
|
|
(dir_b / "file_b.txt").write_text("b")
|
|
# a/link_b -> b and b/link_a -> a
|
|
(dir_a / "link_b").symlink_to(dir_b)
|
|
(dir_b / "link_a").symlink_to(dir_a)
|
|
|
|
result = list_files_recursively(str(dir_a))
|
|
basenames = sorted(os.path.basename(p) for p in result)
|
|
|
|
assert "file_a.txt" in basenames
|
|
assert "file_b.txt" in basenames
|