"""Tests for v1 CV import endpoints (mock LLM mode).""" from __future__ import annotations import base64 import pytest from fastapi.testclient import TestClient @pytest.fixture() def client(): from app.main import app return TestClient(app) class TestCvImport: def test_import_txt_file(self, client): """POST /cv/import with a .txt file returns drafts.""" content = b"John Doe\nSoftware Engineer at TechCorp\n5 years experience with Python" resp = client.post( "/api/cv/import", json={ "filename": "my_cv.txt", "content_base64": base64.b64encode(content).decode(), }, ) assert resp.status_code == 200 data = resp.json() assert "drafts" in data assert len(data["drafts"]) > 0 def test_import_empty_file_422(self, client): """Empty file -> 422.""" content = b"" resp = client.post( "/api/cv/import", json={ "filename": "empty.txt", "content_base64": base64.b64encode(content).decode(), }, ) assert resp.status_code == 422 assert "empty" in resp.text.lower() def test_import_whitespace_only_file_422(self, client): """File with only whitespace -> 422.""" content = b" \n\n\t " resp = client.post( "/api/cv/import", json={ "filename": "blank.txt", "content_base64": base64.b64encode(content).decode(), }, ) assert resp.status_code == 422 assert "empty" in resp.text.lower() def test_import_unsupported_format_422(self, client): """Unsupported file format -> 422.""" content = b"some data" resp = client.post( "/api/cv/import", json={ "filename": "file.xyz", "content_base64": base64.b64encode(content).decode(), }, ) assert resp.status_code == 422 assert "unsupported" in resp.text.lower() def test_import_invalid_base64_422(self, client): """Invalid base64 -> 422.""" resp = client.post( "/api/cv/import", json={ "filename": "file.txt", "content_base64": "!!!not-base64!!!", }, ) assert resp.status_code == 422 def test_import_md_file(self, client): """POST /cv/import with a .md file returns drafts.""" content = b"# Jane Doe\n\n## Experience\nSenior Developer at Acme" resp = client.post( "/api/cv/import", json={ "filename": "cv.md", "content_base64": base64.b64encode(content).decode(), }, ) assert resp.status_code == 200 assert "drafts" in resp.json() def test_import_creates_telemetry(self, client): """CV import should create a task_run entry.""" content = b"Some CV text with experience" client.post( "/api/cv/import", json={ "filename": "cv.txt", "content_base64": base64.b64encode(content).decode(), }, ) resp = client.get("/api/telemetry/tasks") tasks = resp.json() assert any(t["task"] == "cv_extract" for t in tasks) class TestCvImportConfirm: def test_confirm_creates_sections(self, client): """POST /cv/import/confirm creates cv_section rows.""" client.get("/api/profile") resp = client.post( "/api/cv/import/confirm", json={ "drafts": [ { "kind": "experience", "title": "Dev", "org": "Corp", "bullets": ["did stuff"], "tags": ["python"], }, { "kind": "education", "title": "MSc", "org": "Uni", }, ] }, ) assert resp.status_code == 201 data = resp.json() assert data["created"] == 2 assert len(data["sections"]) == 2 def test_confirm_empty_drafts(self, client): """Empty drafts list creates zero sections.""" client.get("/api/profile") resp = client.post( "/api/cv/import/confirm", json={"drafts": []}, ) assert resp.status_code == 201 assert resp.json()["created"] == 0 def test_confirm_sections_appear_in_list(self, client): """Confirmed sections appear in GET /profile/sections.""" client.get("/api/profile") client.post( "/api/cv/import/confirm", json={ "drafts": [ {"kind": "skills", "title": "Python Dev", "bullets": ["FastAPI"]}, ] }, ) resp = client.get("/api/profile/sections") assert resp.status_code == 200 assert any(s["title"] == "Python Dev" for s in resp.json())