Changes committed

This commit is contained in:
2026-06-01 21:49:53 +05:30
parent 8537c653c1
commit 3163bb213e
387 changed files with 21940 additions and 107 deletions

View File

View File

View File

@@ -0,0 +1,224 @@
from __future__ import annotations
import io
import uuid
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from tests.conftest import (
create_test_document,
create_test_page,
create_test_text_block,
create_test_user,
get_auth_headers,
)
class TestUploadDocument:
"""Tests for the document upload endpoint."""
def test_upload_pdf_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
file_content = b"%PDF-1.4 fake pdf content for testing"
response = client.post(
"/api/v1/documents/upload",
files={"file": ("test.pdf", io.BytesIO(file_content), "application/pdf")},
headers=headers,
)
assert response.status_code == 201
data = response.json()
assert data["original_filename"] == "test.pdf"
assert data["content_type"] == "application/pdf"
assert data["status"] == "pending"
assert data["file_size"] == len(file_content)
assert "id" in data
assert "checksum" in data
def test_upload_image_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
# Minimal valid PNG header
png_header = (
b"\x89PNG\r\n\x1a\n"
b"\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
b"\x08\x02\x00\x00\x00\x90wS\xde"
)
response = client.post(
"/api/v1/documents/upload",
files={"file": ("scan.png", io.BytesIO(png_header), "image/png")},
headers=headers,
)
assert response.status_code == 201
data = response.json()
assert data["content_type"] == "image/png"
def test_upload_unsupported_type_rejected(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
response = client.post(
"/api/v1/documents/upload",
files={"file": ("doc.exe", io.BytesIO(b"malware"), "application/octet-stream")},
headers=headers,
)
assert response.status_code in (415, 422)
def test_upload_no_file_rejected(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
response = client.post("/api/v1/documents/upload", headers=headers)
assert response.status_code == 422
class TestGetDocument:
"""Tests for getting a document by ID."""
def test_get_document_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
doc = create_test_document(db, user=user, status="completed")
db.flush()
headers = get_auth_headers(user)
response = client.get(f"/api/v1/documents/{doc.id}", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["id"] == str(doc.id)
assert data["original_filename"] == doc.original_filename
assert data["status"] == "completed"
def test_get_document_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_id = uuid.uuid4()
response = client.get(f"/api/v1/documents/{fake_id}", headers=headers)
assert response.status_code == 404
def test_get_document_invalid_uuid(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/documents/not-a-uuid", headers=headers)
assert response.status_code == 422
class TestListDocuments:
"""Tests for listing documents."""
def test_list_documents_empty(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/documents", headers=headers)
assert response.status_code == 200
data = response.json()
assert "items" in data
assert "total" in data
assert "page" in data
assert "page_size" in data
def test_list_documents_with_data(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
create_test_document(db, user=user, filename="doc1.pdf")
create_test_document(db, user=user, filename="doc2.pdf")
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/documents", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["total"] >= 2
assert len(data["items"]) >= 2
def test_list_documents_pagination(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
for i in range(5):
create_test_document(db, user=user, filename=f"page_doc_{i}.pdf")
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/documents?page=1&page_size=2", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["page"] == 1
assert data["page_size"] == 2
assert len(data["items"]) <= 2
def test_list_documents_status_filter(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
create_test_document(db, user=user, filename="pending.pdf", status="pending")
create_test_document(db, user=user, filename="completed.pdf", status="completed")
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/documents?status=completed", headers=headers)
assert response.status_code == 200
data = response.json()
for item in data["items"]:
assert item["status"] == "completed"
class TestDeleteDocument:
"""Tests for deleting a document."""
def test_delete_document_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
doc = create_test_document(db, user=user)
db.flush()
headers = get_auth_headers(user)
response = client.delete(f"/api/v1/documents/{doc.id}", headers=headers)
assert response.status_code == 200
data = response.json()
assert "message" in data
# Verify document is gone
get_response = client.get(f"/api/v1/documents/{doc.id}", headers=headers)
assert get_response.status_code == 404
def test_delete_document_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_id = uuid.uuid4()
response = client.delete(f"/api/v1/documents/{fake_id}", headers=headers)
assert response.status_code == 404
class TestGetDocumentTemplateMatches:
"""Tests for document template match retrieval."""
def test_get_matches_empty(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
doc = create_test_document(db, user=user, status="completed")
db.flush()
headers = get_auth_headers(user)
response = client.get(f"/api/v1/documents/{doc.id}/template", headers=headers)
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
assert len(data) == 0
def test_get_matches_document_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_id = uuid.uuid4()
response = client.get(f"/api/v1/documents/{fake_id}/template", headers=headers)
assert response.status_code == 404

View File

View File

@@ -0,0 +1,254 @@
from __future__ import annotations
import uuid
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from tests.conftest import (
create_test_document,
create_test_fingerprint,
create_test_page,
create_test_template,
create_test_text_block,
create_test_user,
get_auth_headers,
)
class TestListTemplates:
"""Tests for listing templates."""
def test_list_templates_empty(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/templates", headers=headers)
assert response.status_code == 200
data = response.json()
assert "items" in data
assert "total" in data
assert "page" in data
def test_list_templates_with_data(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
create_test_template(db, name="Template_A", created_by=user)
create_test_template(db, name="Template_B", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/templates", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["total"] >= 2
def test_list_templates_pagination(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
for i in range(5):
create_test_template(db, name=f"PagTemplate_{i}", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.get("/api/v1/templates?page=1&page_size=2", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["page"] == 1
assert data["page_size"] == 2
assert len(data["items"]) <= 2
class TestGetTemplate:
"""Tests for getting a template by ID."""
def test_get_template_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
template = create_test_template(db, name="GetMe", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.get(f"/api/v1/templates/{template.id}", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["id"] == str(template.id)
assert data["name"] == "GetMe"
assert data["page_width"] == 612.0
assert data["page_height"] == 792.0
assert data["is_active"] is True
def test_get_template_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_id = uuid.uuid4()
response = client.get(f"/api/v1/templates/{fake_id}", headers=headers)
assert response.status_code == 404
def test_get_template_includes_components(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
template = create_test_template(db, name="ComponentTemplate", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.get(f"/api/v1/templates/{template.id}", headers=headers)
assert response.status_code == 200
data = response.json()
assert "cells" in data
assert "regions" in data
assert "table_formats" in data
assert "watermarks" in data
assert "image_regions" in data
class TestDeleteTemplate:
"""Tests for template soft-deletion."""
def test_delete_template_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
template = create_test_template(db, name="DeleteMe", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.delete(f"/api/v1/templates/{template.id}", headers=headers)
assert response.status_code == 200
data = response.json()
assert "message" in data
# Verify template is deactivated (soft-deleted), not hard-deleted
get_response = client.get(f"/api/v1/templates/{template.id}", headers=headers)
assert get_response.status_code == 200
assert get_response.json()["is_active"] is False
def test_delete_template_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_id = uuid.uuid4()
response = client.delete(f"/api/v1/templates/{fake_id}", headers=headers)
assert response.status_code == 404
class TestMatchTemplate:
"""Tests for document-to-template matching endpoint."""
def test_match_document_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_doc_id = uuid.uuid4()
response = client.post(
"/api/v1/templates/match",
json={"document_id": str(fake_doc_id), "min_confidence": 0.5, "max_results": 5},
headers=headers,
)
assert response.status_code == 404
def test_match_document_not_completed(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
doc = create_test_document(db, user=user, status="pending")
db.flush()
headers = get_auth_headers(user)
response = client.post(
"/api/v1/templates/match",
json={"document_id": str(doc.id), "min_confidence": 0.5, "max_results": 5},
headers=headers,
)
assert response.status_code == 400
def test_match_completed_document_no_templates(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
doc = create_test_document(db, user=user, status="completed")
page = create_test_page(db, doc)
create_test_text_block(db, page, text="Content")
db.flush()
headers = get_auth_headers(user)
response = client.post(
"/api/v1/templates/match",
json={"document_id": str(doc.id), "min_confidence": 0.0, "max_results": 5},
headers=headers,
)
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
class TestRenderTemplate:
"""Tests for template rendering endpoint."""
def test_render_template_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
db.flush()
headers = get_auth_headers(user)
fake_id = uuid.uuid4()
response = client.post(
"/api/v1/templates/render",
json={
"template_id": str(fake_id),
"data": {},
},
headers=headers,
)
assert response.status_code == 404
def test_render_inactive_template(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
template = create_test_template(db, name="InactiveRender", created_by=user)
template.is_active = False
db.flush()
headers = get_auth_headers(user)
response = client.post(
"/api/v1/templates/render",
json={
"template_id": str(template.id),
"data": {},
},
headers=headers,
)
assert response.status_code == 400
def test_render_template_success(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
template = create_test_template(db, name="RenderOK", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.post(
"/api/v1/templates/render",
json={
"template_id": str(template.id),
"data": {"field_1": "Hello World"},
"output_filename": "test_render.pdf",
},
headers=headers,
)
assert response.status_code == 200
data = response.json()
assert data["filename"] == "test_render.pdf"
assert data["file_size"] > 0
assert data["page_count"] == template.page_count
assert "output_path" in data
assert "rendered_at" in data
class TestDownloadRenderedPDF:
"""Tests for downloading rendered PDFs."""
def test_download_not_found(self, client: TestClient, db: Session) -> None:
user = create_test_user(db)
template = create_test_template(db, name="DLTemplate", created_by=user)
db.flush()
headers = get_auth_headers(user)
response = client.get(
f"/api/v1/templates/{template.id}/download?filename=nonexistent.pdf",
headers=headers,
)
assert response.status_code == 404