from fastapi.testclient import TestClient import pytest from test_app import load_app_module def test_cv_evaluation_has_structured_semantic_rules_and_requirements_only_context(monkeypatch): module = load_app_module(monkeypatch, ollama_model="qwen2.5:7b", service_token="local-proof-token") expected = {"verdict": "supported", "coverageComplete": True, "claims": [ {"text": "Utviklet API-er.", "verdict": "supported", "sourceQuotes": ["Built APIs."]}]} def evaluate(prompt): assert "faithful paraphrases, shortening" in prompt assert "English/Bokmal translations" in prompt assert "Job/context text describes requirements ONLY" in prompt assert "Candidate source is the ONLY evidence" in prompt assert "Assess ALL factual claims" in prompt assert "coverage is complete and every entry is supported" in prompt assert "Employer requires Kubernetes." in prompt assert module._ai_task_type.get() == "cv-rewrite" return expected monkeypatch.setattr(module, "_ollama_generate_json", evaluate) client = TestClient(module.app) body = {"candidate_source": "Built APIs.", "proposal": "Utviklet API-er.", "context_only": "Employer requires Kubernetes."} assert client.post("/cv/evaluate-rewrite", json=body).status_code == 401 response = client.post("/cv/evaluate-rewrite", json=body, headers={"X-Ai-Service-Token": "local-proof-token"}) assert response.status_code == 200 assert response.json() == {"assessment": expected} @pytest.mark.parametrize("source,proposal,context", [ ("", "Built APIs.", ""), (" ", "Built APIs.", ""), ("Built APIs.", "", ""), ("x" * 20000, "New proposal.", ""), ("Built APIs.", "Proposal.", "x" * 6001), ]) def test_cv_evaluation_rejects_empty_or_oversized_inputs_before_generation(monkeypatch, source, proposal, context): module = load_app_module(monkeypatch) monkeypatch.setattr(module, "_ollama_generate_json", lambda _: pytest.fail("Invalid input must not generate")) response = TestClient(module.app).post("/cv/evaluate-rewrite", json={"candidate_source": source, "proposal": proposal, "context_only": context}) assert response.status_code == 422 def test_cv_evaluation_uses_existing_local_first_privacy_gate(monkeypatch): monkeypatch.setenv("AI_PROVIDER", "groq") monkeypatch.setenv("GROQ_API_KEY", "synthetic-test-key") module = load_app_module(monkeypatch, ollama_model="qwen2.5:7b", external_ai_enabled=True) providers = [] def generate(provider, prompt, **kwargs): providers.append(provider) assert kwargs["json_mode"] is True if provider == "ollama": raise module._ProviderFailure(provider, "provider_unavailable", 503) return '{"verdict":"unknown","coverageComplete":false,"claims":[]}' monkeypatch.setattr(module, "_generate_from_provider", generate) client = TestClient(module.app) body = {"candidate_source": "Built APIs.", "proposal": "Led engineers."} assert client.post("/cv/evaluate-rewrite", json=body).status_code == 503 assert providers == ["ollama"] providers.clear() response = client.post("/cv/evaluate-rewrite", json=body, headers={"X-Ai-External-Allowed": "true"}) assert response.status_code == 200 assert providers == ["ollama", "groq"] assert response.json()["assessment"]["verdict"] == "unknown" def test_cv_evaluation_rejects_non_object_provider_assessment(monkeypatch): module = load_app_module(monkeypatch) monkeypatch.setattr(module, "_ollama_generate_json", lambda _: []) response = TestClient(module.app).post("/cv/evaluate-rewrite", json={"candidate_source": "Built APIs.", "proposal": "Developed APIs."}) assert response.status_code == 502 @pytest.mark.parametrize("output_mode", [None, "text", "cv_blocks_json"]) def test_cv_rewrite_typed_format_preserves_legacy_text_and_document_json(monkeypatch, output_mode): module = load_app_module(monkeypatch) result = '[{"id":"section:summary","title":"Profile","items":["Developed APIs."]}]' if output_mode == "cv_blocks_json" else "Developed APIs." def generate(prompt): if output_mode == "cv_blocks_json": assert "Return ONLY a valid JSON array" in prompt assert "Preserve every original block id exactly once" in prompt assert "same title, subtitle and items fields/types" in prompt assert "No JSON." not in prompt assert "Preferred whole-CV structure" not in prompt assert "sensible headings and bullets" not in prompt else: assert "Return ONLY the final CV text" in prompt assert "No JSON." in prompt assert module._ai_task_type.get() == "cv-rewrite" return result monkeypatch.setattr(module, "_ollama_generate_text", generate) body = {"instruction": "Improve clarity.", "text": "Built APIs."} if output_mode is not None: body["output_mode"] = output_mode response = TestClient(module.app).post("/cv/rewrite", json=body) assert response.status_code == 200 assert response.json() == {"rewritten_text": result} def test_cv_rewrite_rejects_unknown_typed_output_mode_before_generation(monkeypatch): module = load_app_module(monkeypatch) monkeypatch.setattr(module, "_ollama_generate_text", lambda _: pytest.fail("Unknown mode must not generate")) response = TestClient(module.app).post("/cv/rewrite", json={"instruction": "Improve", "text": "Built APIs.", "output_mode": "untrusted-mode"}) assert response.status_code == 422