import os import uuid from datetime import date import pytest from fastapi.testclient import TestClient # Ensure required env vars for app import/config os.environ.setdefault("SECRET_KEY", "x" * 32) os.environ.setdefault("DATABASE_URL", "sqlite:////tmp/delphi_test.sqlite") from app.main import app # noqa: E402 from app.auth.security import get_current_user # noqa: E402 from tests.helpers import assert_validation_error, assert_http_error # noqa: E402 @pytest.fixture(scope="module") def client(): # Override auth to bypass JWT for these tests class _User: def __init__(self): self.id = "test" self.username = "tester" self.is_admin = True self.is_active = True app.dependency_overrides[get_current_user] = lambda: _User() try: yield TestClient(app) finally: app.dependency_overrides.pop(get_current_user, None) def _create_customer(client: TestClient) -> str: customer_id = f"FILE-CUST-{uuid.uuid4().hex[:8]}" payload = {"id": customer_id, "last": "FileOwner", "email": "owner@example.com"} resp = client.post("/api/customers/", json=payload) assert resp.status_code == 200 return customer_id def _valid_file_payload(file_no: str, owner_id: str) -> dict: return { "file_no": file_no, "id": owner_id, "regarding": "Matter description", "empl_num": "E01", "file_type": "CIVIL", "opened": date.today().isoformat(), "status": "ACTIVE", "rate_per_hour": 200.0, "memo": "Created by pytest", } def test_create_file_schema_validation_errors(client: TestClient): owner_id = _create_customer(client) file_no = f"F-{uuid.uuid4().hex[:6]}" # Missing required fields should trigger validation errors resp = client.post("/api/files/", json={}) assert_validation_error(resp, "file_no") # Wrong types: rate_per_hour as string, opened wrong format bad = _valid_file_payload(file_no, owner_id) bad["rate_per_hour"] = "twenty" bad["opened"] = "not-a-date" resp = client.post("/api/files/", json=bad) assert_validation_error(resp, "rate_per_hour") assert_validation_error(resp, "opened") def test_create_file_and_duplicate_file_no_returns_400(client: TestClient): owner_id = _create_customer(client) file_no = f"F-{uuid.uuid4().hex[:6]}" payload = _valid_file_payload(file_no, owner_id) # First create OK resp = client.post("/api/files/", json=payload) assert resp.status_code == 200 # Duplicate should be 400 with envelope resp = client.post("/api/files/", json=payload) assert_http_error(resp, 400, "File number already exists") # Cleanup resp = client.delete(f"/api/files/{file_no}") assert resp.status_code == 200 def test_get_update_delete_missing_file_returns_404(client: TestClient): missing = f"NOFILE-{uuid.uuid4().hex[:6]}" resp = client.get(f"/api/files/{missing}") assert_http_error(resp, 404, "File not found") resp = client.put(f"/api/files/{missing}", json={"status": "ACTIVE"}) assert_http_error(resp, 404, "File not found") resp = client.delete(f"/api/files/{missing}") assert_http_error(resp, 404, "File not found") def test_financial_and_client_info_404_for_missing_file(client: TestClient): missing = f"NOFILE-{uuid.uuid4().hex[:6]}" resp = client.get(f"/api/files/{missing}/financial-summary") assert_http_error(resp, 404, "File not found") resp = client.get(f"/api/files/{missing}/client-info") assert_http_error(resp, 404, "File not found") def test_list_and_advanced_search_param_validation(client: TestClient): resp = client.get("/api/files/?limit=0") assert_validation_error(resp, "limit") resp = client.get("/api/files/?skip=-1") assert_validation_error(resp, "skip")