- Extends GET /api/v1/tags with sort=count_desc and min_count query params - New TagsComponent at /tags (public, no auth guard) shows all tags sorted by image count - Clicking a tag navigates to /?tags=<name> for a pre-filtered library view - LibraryComponent reads ?tags= query param on init to support deep-linking from tag browser - Library header gains a "Browse tags" link to /tags for discoverability - All 15 TDD tasks complete; ruff, ng lint, and ng build clean Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
36 lines
1.1 KiB
Python
36 lines
1.1 KiB
Python
import pytest
|
|
|
|
from app.validation import FileSizeError, MimeTypeError, validate_file_size, validate_mime_type
|
|
|
|
ACCEPTED_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp"]
|
|
REJECTED_TYPES = ["application/pdf", "video/mp4", "text/plain", "application/octet-stream"]
|
|
|
|
|
|
@pytest.mark.parametrize("mime_type", ACCEPTED_TYPES)
|
|
def test_mime_type_accepts_images(mime_type):
|
|
validate_mime_type(mime_type) # should not raise
|
|
|
|
|
|
@pytest.mark.parametrize("mime_type", REJECTED_TYPES)
|
|
def test_mime_type_rejects_non_images(mime_type):
|
|
with pytest.raises(MimeTypeError):
|
|
validate_mime_type(mime_type)
|
|
|
|
|
|
def test_file_size_accepts_within_limit():
|
|
validate_file_size(1024, max_bytes=52_428_800) # should not raise
|
|
|
|
|
|
def test_file_size_accepts_exact_limit():
|
|
validate_file_size(52_428_800, max_bytes=52_428_800) # should not raise
|
|
|
|
|
|
def test_file_size_rejects_over_limit():
|
|
with pytest.raises(FileSizeError):
|
|
validate_file_size(52_428_801, max_bytes=52_428_800)
|
|
|
|
|
|
def test_file_size_rejects_zero():
|
|
with pytest.raises(FileSizeError):
|
|
validate_file_size(0, max_bytes=52_428_800)
|