219 lines
6.2 KiB
Python
219 lines
6.2 KiB
Python
"""Shared fixtures for the test suite."""
|
|
|
|
import argparse
|
|
import shutil
|
|
import zipfile
|
|
from collections.abc import Generator
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from httpx import ASGITransport, AsyncClient
|
|
|
|
import main
|
|
|
|
|
|
def _reset_state() -> None:
|
|
"""Reset all global state to defaults."""
|
|
main.file_mapping.clear()
|
|
main.indexers.clear()
|
|
main.sorted_hashes.clear()
|
|
main.navigate_enabled = False
|
|
main.root_path = ""
|
|
main.app.root_path = ""
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def reset_globals() -> Generator[None]:
|
|
"""Reset global state before and after each test."""
|
|
_reset_state()
|
|
yield
|
|
_reset_state()
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_files(tmp_path: Path) -> dict[str, Path]:
|
|
"""Create a directory with sample files for testing.
|
|
|
|
Returns:
|
|
Dict mapping logical names to file paths.
|
|
"""
|
|
subdir = tmp_path / "subdir"
|
|
subdir.mkdir()
|
|
|
|
files: dict[str, Path] = {}
|
|
files["root_file"] = tmp_path / "root.txt"
|
|
files["root_file"].write_text("root content")
|
|
|
|
files["sub_file"] = subdir / "nested.txt"
|
|
files["sub_file"].write_text("nested content")
|
|
|
|
files["binary_file"] = tmp_path / "data.bin"
|
|
files["binary_file"].write_bytes(b"\x00\x01\x02\x03")
|
|
|
|
files["image_file"] = tmp_path / "photo.jpg"
|
|
files["image_file"].write_bytes(b"\xff\xd8\xff\xe0fake_jpeg_data")
|
|
|
|
files["video_file"] = tmp_path / "clip.mp4"
|
|
files["video_file"].write_bytes(b"\x00\x00\x00\x1cftypfake_mp4_data")
|
|
|
|
return files
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_zip(tmp_path: Path) -> dict[str, Path]:
|
|
"""Create a ZIP file with sample files for testing.
|
|
|
|
Returns:
|
|
Dict mapping logical names to file paths inside the zip.
|
|
"""
|
|
zip_path = tmp_path / "test_archive.zip"
|
|
inner_files: dict[str, Path] = {}
|
|
|
|
with zipfile.ZipFile(zip_path, "w") as zf:
|
|
zf.writestr("top.txt", "top level content")
|
|
inner_files["top"] = Path("top.txt")
|
|
|
|
zf.writestr("folder/deep.txt", "deep content")
|
|
inner_files["deep"] = Path("folder/deep.txt")
|
|
|
|
zf.writestr("folder/image.png", b"\x89PNG fake png")
|
|
inner_files["image"] = Path("folder/image.png")
|
|
|
|
return inner_files
|
|
|
|
|
|
@pytest.fixture
|
|
def args_directory(sample_files: dict[str, Path], tmp_path: Path) -> argparse.Namespace:
|
|
"""Argparse namespace pointing at the sample directory."""
|
|
return argparse.Namespace(
|
|
source=str(tmp_path),
|
|
host="127.0.0.1",
|
|
port=0,
|
|
salt="test-salt",
|
|
navigate=False,
|
|
root_path=None,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def args_zip(sample_zip: dict[str, Path], tmp_path: Path) -> argparse.Namespace:
|
|
"""Argparse namespace pointing at the sample zip."""
|
|
return argparse.Namespace(
|
|
source=str(tmp_path / "test_archive.zip"),
|
|
host="127.0.0.1",
|
|
port=0,
|
|
salt="test-salt",
|
|
navigate=False,
|
|
root_path=None,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def args_zip_navigate(
|
|
sample_zip: dict[str, Path], tmp_path: Path
|
|
) -> argparse.Namespace:
|
|
"""Argparse namespace pointing at the sample zip with navigate enabled."""
|
|
return argparse.Namespace(
|
|
source=str(tmp_path / "test_archive.zip"),
|
|
host="127.0.0.1",
|
|
port=0,
|
|
salt="test-salt",
|
|
navigate=True,
|
|
root_path=None,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def initialized_dir(args_directory: argparse.Namespace) -> None:
|
|
"""Initialize the server with sample directory files."""
|
|
main.initialize_server(args_directory)
|
|
|
|
|
|
@pytest.fixture
|
|
def initialized_zip(args_zip: argparse.Namespace) -> None:
|
|
"""Initialize the server with sample zip files."""
|
|
main.initialize_server(args_zip)
|
|
|
|
|
|
@pytest.fixture
|
|
async def client_dir(initialized_dir: None) -> Generator[AsyncClient]:
|
|
"""Async HTTP client against the app initialized with directory files."""
|
|
transport = ASGITransport(app=main.app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
|
yield ac
|
|
|
|
|
|
@pytest.fixture
|
|
async def client_zip(initialized_zip: None) -> Generator[AsyncClient]:
|
|
"""Async HTTP client against the app initialized with zip files."""
|
|
transport = ASGITransport(app=main.app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
|
yield ac
|
|
|
|
|
|
@pytest.fixture
|
|
def initialized_zip_navigate(args_zip_navigate: argparse.Namespace) -> None:
|
|
"""Initialize the server with sample zip files and navigate enabled."""
|
|
main.initialize_server(args_zip_navigate)
|
|
|
|
|
|
@pytest.fixture
|
|
async def client_zip_navigate(
|
|
initialized_zip_navigate: None,
|
|
) -> Generator[AsyncClient]:
|
|
"""Async HTTP client against the app initialized with zip + navigate."""
|
|
transport = ASGITransport(app=main.app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
|
yield ac
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_encrypted_zip(tmp_path: Path) -> tuple[Path, dict[str, str], str]:
|
|
"""Copy the pre-existing testfile.zip to a temp location.
|
|
|
|
Returns:
|
|
Tuple of (zip_path, inner_files dict, password).
|
|
inner_files maps logical names to internal paths.
|
|
"""
|
|
src = Path(__file__).parent / "testfile.zip"
|
|
zip_path = tmp_path / "testfile.zip"
|
|
shutil.copy2(src, zip_path)
|
|
password = "password"
|
|
inner_files: dict[str, str] = {
|
|
"encrypted": "encrypted.txt",
|
|
"unencrypted": "unencrypted.txt",
|
|
}
|
|
return zip_path, inner_files, password
|
|
|
|
|
|
@pytest.fixture
|
|
def args_encrypted_zip(
|
|
sample_encrypted_zip: tuple[Path, dict[str, str], str], tmp_path: Path
|
|
) -> argparse.Namespace:
|
|
"""Argparse namespace pointing at the encrypted sample zip."""
|
|
zip_path, _, _ = sample_encrypted_zip
|
|
return argparse.Namespace(
|
|
source=str(zip_path),
|
|
host="127.0.0.1",
|
|
port=0,
|
|
salt="test-salt",
|
|
navigate=False,
|
|
root_path=None,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def initialized_encrypted_zip(args_encrypted_zip: argparse.Namespace) -> None:
|
|
"""Initialize the server with encrypted zip files."""
|
|
main.initialize_server(args_encrypted_zip)
|
|
|
|
|
|
@pytest.fixture
|
|
async def client_encrypted_zip(
|
|
initialized_encrypted_zip: None,
|
|
) -> Generator[AsyncClient]:
|
|
"""Async HTTP client against the app initialized with encrypted zip files."""
|
|
transport = ASGITransport(app=main.app)
|
|
async with AsyncClient(transport=transport, base_url="http://test") as ac:
|
|
yield ac
|