mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-06-11 23:04:41 -04:00
- Added max image sizes and compression for frontend cached images - Fixed various UI issues with dropdown placement and animation
95 lines
2.8 KiB
Python
95 lines
2.8 KiB
Python
"""Tests for targeted image cache safety and fetch fallbacks."""
|
|
|
|
from io import BytesIO
|
|
|
|
import requests
|
|
from PIL import Image
|
|
|
|
from shelfmark.core.image_cache import (
|
|
ImageCacheService,
|
|
build_variant_cache_id,
|
|
create_image_variant,
|
|
normalize_variant_dimension,
|
|
normalize_variant_format,
|
|
)
|
|
|
|
|
|
def _make_image_bytes(
|
|
*, width: int = 400, height: int = 600, image_format: str = "JPEG", color: str = "navy"
|
|
) -> bytes:
|
|
buffer = BytesIO()
|
|
Image.new("RGB", (width, height), color=color).save(buffer, format=image_format)
|
|
return buffer.getvalue()
|
|
|
|
|
|
def test_is_safe_url_rejects_invalid_ipv6_url() -> None:
|
|
assert ImageCacheService._is_safe_url("http://[") is False
|
|
|
|
|
|
def test_fetch_and_cache_returns_none_on_request_exception(tmp_path, monkeypatch) -> None:
|
|
cache = ImageCacheService(tmp_path)
|
|
monkeypatch.setattr(cache, "_is_safe_url", lambda _url: True)
|
|
|
|
def fake_get(*args, **kwargs):
|
|
raise requests.exceptions.TooManyRedirects("too many redirects")
|
|
|
|
monkeypatch.setattr("shelfmark.core.image_cache.requests.get", fake_get)
|
|
|
|
assert cache.fetch_and_cache("cover-1", "https://example.com/cover.jpg") is None
|
|
assert "cover-1" not in cache._index
|
|
|
|
|
|
def test_create_image_variant_resizes_and_transcodes_to_webp() -> None:
|
|
variant = create_image_variant(
|
|
_make_image_bytes(),
|
|
width=120,
|
|
height=180,
|
|
image_format="webp",
|
|
)
|
|
|
|
assert variant is not None
|
|
variant_bytes, content_type = variant
|
|
assert content_type == "image/webp"
|
|
|
|
with Image.open(BytesIO(variant_bytes)) as image:
|
|
assert image.size == (120, 180)
|
|
|
|
|
|
def test_create_image_variant_preserves_aspect_ratio_for_single_dimension() -> None:
|
|
variant = create_image_variant(
|
|
_make_image_bytes(),
|
|
width=120,
|
|
image_format="jpeg",
|
|
)
|
|
|
|
assert variant is not None
|
|
variant_bytes, content_type = variant
|
|
assert content_type == "image/jpeg"
|
|
|
|
with Image.open(BytesIO(variant_bytes)) as image:
|
|
assert image.size == (120, 180)
|
|
|
|
|
|
def test_create_image_variant_returns_none_when_no_change_needed() -> None:
|
|
image_bytes = _make_image_bytes(image_format="WEBP")
|
|
|
|
assert create_image_variant(image_bytes, image_format="webp") is None
|
|
|
|
|
|
def test_variant_helpers_normalize_requested_variant_values() -> None:
|
|
assert normalize_variant_dimension("240") == 240
|
|
assert normalize_variant_dimension("0") is None
|
|
assert normalize_variant_dimension("99999") == 1024
|
|
assert normalize_variant_format("jpg") == "jpeg"
|
|
assert normalize_variant_format("weBp") == "webp"
|
|
assert normalize_variant_format("gif") is None
|
|
assert (
|
|
build_variant_cache_id(
|
|
"cover-123",
|
|
width=120,
|
|
height=180,
|
|
image_format="webp",
|
|
)
|
|
== "cover-123__w120_h180_fwebp"
|
|
)
|