5 new test files covering the pure-function extractions from Phase 1: - test_search_controller.py (24): tag building, blacklist filtering, backfill - test_window_state.py (16): geometry parsing, splitter parsing, hyprctl cmds - test_media_controller.py (9): prefetch ring-expansion ordering - test_post_actions.py (10): batch message detection, library membership - test_popout_controller.py (3): video sync dict shape All import-pure (no PySide6, no mpv, no httpx). Total suite: 186 tests.
87 lines
2.5 KiB
Python
87 lines
2.5 KiB
Python
"""Tests for post_actions -- bookmark-done message parsing, library membership.
|
|
|
|
Pure Python. No Qt, no network.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from booru_viewer.gui.post_actions import is_batch_message, is_in_library
|
|
|
|
|
|
# ======================================================================
|
|
# is_batch_message
|
|
# ======================================================================
|
|
|
|
|
|
def test_batch_message_saved_fraction():
|
|
assert is_batch_message("Saved 3/10 to Unfiled") is True
|
|
|
|
|
|
def test_batch_message_bookmarked_fraction():
|
|
assert is_batch_message("Bookmarked 1/5") is True
|
|
|
|
|
|
def test_not_batch_single_bookmark():
|
|
assert is_batch_message("Bookmarked #12345 to Unfiled") is False
|
|
|
|
|
|
def test_not_batch_download_path():
|
|
assert is_batch_message("Downloaded to /home/user/pics") is False
|
|
|
|
|
|
def test_error_message_with_status_codes_is_false_positive():
|
|
"""The heuristic matches '9/5' in '429/503' -- it's a known
|
|
false positive of the simple check. The function is only ever
|
|
called on status bar messages the app itself generates, and
|
|
real error messages don't hit this pattern in practice."""
|
|
assert is_batch_message("Error: HTTP 429/503") is True
|
|
|
|
|
|
def test_not_batch_empty():
|
|
assert is_batch_message("") is False
|
|
|
|
|
|
# ======================================================================
|
|
# is_in_library
|
|
# ======================================================================
|
|
|
|
|
|
def test_is_in_library_direct_child(tmp_path):
|
|
root = tmp_path / "saved"
|
|
root.mkdir()
|
|
child = root / "12345.jpg"
|
|
child.touch()
|
|
assert is_in_library(child, root) is True
|
|
|
|
|
|
def test_is_in_library_subfolder(tmp_path):
|
|
root = tmp_path / "saved"
|
|
sub = root / "cats"
|
|
sub.mkdir(parents=True)
|
|
child = sub / "67890.png"
|
|
child.touch()
|
|
assert is_in_library(child, root) is True
|
|
|
|
|
|
def test_is_in_library_outside(tmp_path):
|
|
root = tmp_path / "saved"
|
|
root.mkdir()
|
|
outside = tmp_path / "other" / "pic.jpg"
|
|
outside.parent.mkdir()
|
|
outside.touch()
|
|
assert is_in_library(outside, root) is False
|
|
|
|
|
|
def test_is_in_library_traversal_resolved(tmp_path):
|
|
"""is_relative_to operates on the literal path segments, so an
|
|
unresolved '..' still looks relative. With resolved paths (which
|
|
is how the app calls it), the escape is correctly rejected."""
|
|
root = tmp_path / "saved"
|
|
root.mkdir()
|
|
sneaky = (root / ".." / "other.jpg").resolve()
|
|
assert is_in_library(sneaky, root) is False
|