Files
invoice-master-poc-v2/tests/web/test_admin_annotations.py
Yaojia Wang 58bf75db68 WIP
2026-01-27 00:47:10 +01:00

198 lines
5.6 KiB
Python

"""
Tests for Admin Annotation Routes.
"""
import pytest
from datetime import datetime
from unittest.mock import MagicMock, patch
from uuid import UUID
from fastapi import HTTPException
from src.data.admin_models import AdminAnnotation, AdminDocument, FIELD_CLASSES
from src.web.api.v1.admin.annotations import _validate_uuid, create_annotation_router
from src.web.schemas.admin import (
AnnotationCreate,
AnnotationUpdate,
AutoLabelRequest,
BoundingBox,
)
# Test UUIDs
TEST_DOC_UUID = "550e8400-e29b-41d4-a716-446655440000"
TEST_ANN_UUID = "660e8400-e29b-41d4-a716-446655440001"
TEST_TOKEN = "test-admin-token-12345"
class TestAnnotationRouterCreation:
"""Tests for annotation router creation."""
def test_creates_router_with_endpoints(self):
"""Test router is created with expected endpoints."""
router = create_annotation_router()
# Get route paths (includes prefix)
paths = [route.path for route in router.routes]
# Paths include the /admin/documents prefix
assert any("{document_id}/annotations" in p for p in paths)
assert any("{annotation_id}" in p for p in paths)
assert any("auto-label" in p for p in paths)
assert any("images" in p for p in paths)
class TestAnnotationCreateSchema:
"""Tests for AnnotationCreate schema."""
def test_valid_annotation(self):
"""Test valid annotation creation."""
ann = AnnotationCreate(
page_number=1,
class_id=0,
bbox=BoundingBox(x=100, y=100, width=200, height=50),
text_value="12345",
)
assert ann.page_number == 1
assert ann.class_id == 0
assert ann.bbox.x == 100
assert ann.text_value == "12345"
def test_class_id_range(self):
"""Test class_id must be 0-9."""
# Valid class IDs
for class_id in range(10):
ann = AnnotationCreate(
page_number=1,
class_id=class_id,
bbox=BoundingBox(x=0, y=0, width=100, height=50),
)
assert ann.class_id == class_id
def test_bbox_validation(self):
"""Test bounding box validation."""
bbox = BoundingBox(x=0, y=0, width=100, height=50)
assert bbox.width >= 1
assert bbox.height >= 1
class TestAnnotationUpdateSchema:
"""Tests for AnnotationUpdate schema."""
def test_partial_update(self):
"""Test partial update with only some fields."""
update = AnnotationUpdate(
text_value="new value",
)
assert update.text_value == "new value"
assert update.class_id is None
assert update.bbox is None
def test_bbox_update(self):
"""Test bounding box update."""
update = AnnotationUpdate(
bbox=BoundingBox(x=50, y=50, width=150, height=75),
)
assert update.bbox.x == 50
assert update.bbox.width == 150
class TestAutoLabelRequestSchema:
"""Tests for AutoLabelRequest schema."""
def test_valid_request(self):
"""Test valid auto-label request."""
request = AutoLabelRequest(
field_values={
"InvoiceNumber": "12345",
"Amount": "1000.00",
},
replace_existing=True,
)
assert len(request.field_values) == 2
assert request.field_values["InvoiceNumber"] == "12345"
assert request.replace_existing is True
def test_requires_field_values(self):
"""Test that field_values is required."""
with pytest.raises(Exception):
AutoLabelRequest(replace_existing=True)
class TestFieldClasses:
"""Tests for field class mapping."""
def test_all_classes_defined(self):
"""Test all 10 field classes are defined."""
assert len(FIELD_CLASSES) == 10
def test_class_ids_sequential(self):
"""Test class IDs are 0-9."""
assert set(FIELD_CLASSES.keys()) == set(range(10))
def test_known_field_names(self):
"""Test known field names are present."""
names = list(FIELD_CLASSES.values())
assert "invoice_number" in names
assert "invoice_date" in names
assert "amount" in names
assert "bankgiro" in names
assert "ocr_number" in names
class TestAnnotationModel:
"""Tests for AdminAnnotation model."""
def test_annotation_creation(self):
"""Test annotation model creation."""
ann = AdminAnnotation(
document_id=UUID(TEST_DOC_UUID),
page_number=1,
class_id=0,
class_name="invoice_number",
x_center=0.5,
y_center=0.5,
width=0.2,
height=0.05,
bbox_x=100,
bbox_y=100,
bbox_width=200,
bbox_height=50,
text_value="12345",
confidence=0.95,
source="manual",
)
assert str(ann.document_id) == TEST_DOC_UUID
assert ann.class_id == 0
assert ann.x_center == 0.5
assert ann.source == "manual"
def test_normalized_coordinates(self):
"""Test normalized coordinates are 0-1 range."""
# Valid normalized coords
ann = AdminAnnotation(
document_id=UUID(TEST_DOC_UUID),
page_number=1,
class_id=0,
class_name="test",
x_center=0.5,
y_center=0.5,
width=0.2,
height=0.05,
bbox_x=0,
bbox_y=0,
bbox_width=100,
bbox_height=50,
)
assert 0 <= ann.x_center <= 1
assert 0 <= ann.y_center <= 1
assert 0 <= ann.width <= 1
assert 0 <= ann.height <= 1