Spaces:
Running
Running
File size: 5,368 Bytes
2276aab 3f28422 2276aab 3f28422 2276aab 3f28422 2276aab 3f28422 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | """
Unit tests for Pseudogen FastAPI app.
Tests GenerateRequest validation, style/detail handling, and generate endpoint with mocked LLM.
Auth is overridden so generate endpoints receive a fake user.
"""
import pytest
from fastapi.testclient import TestClient
from unittest.mock import patch
from app import app, GenerateRequest
from auth import get_current_user
# Override auth so generate endpoints see a fake user (plan from user, not header)
FAKE_USER_FREE = {"id": 1, "email": "test@test.com", "plan": "free"}
FAKE_USER_PREMIUM = {"id": 2, "email": "premium@test.com", "plan": "premium"}
async def _fake_user_free():
return FAKE_USER_FREE
async def _fake_user_premium():
return FAKE_USER_PREMIUM
app.dependency_overrides[get_current_user] = _fake_user_free
client = TestClient(app)
def test_root_returns_service_info():
"""GET / returns service info and docs link."""
r = client.get("/")
assert r.status_code == 200
data = r.json()
assert data.get("service") == "Pseudogen API"
assert data.get("docs") == "/docs"
assert "generate-pseudocode" in data.get("generate", "")
def test_generate_request_validates_problem_description_min_length():
"""GenerateRequest rejects empty problem_description."""
with patch("app.call_llm") as mock_llm:
mock_llm.return_value = "BEGIN\nEND"
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "",
"style": "Academic",
"detail": "Concise",
},
)
assert r.status_code == 422
def test_generate_request_validates_style_regex():
"""GenerateRequest rejects invalid style."""
with patch("app.call_llm"):
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "Sort a list",
"style": "InvalidStyle",
"detail": "Concise",
},
)
assert r.status_code == 422
def test_generate_request_validates_detail_regex():
"""GenerateRequest rejects invalid detail."""
with patch("app.call_llm"):
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "Sort a list",
"style": "Academic",
"detail": "Medium",
},
)
assert r.status_code == 422
@pytest.mark.parametrize("style", ["Academic", "Developer-Friendly", "English-Like", "Step-by-Step"])
@pytest.mark.parametrize("detail", ["Concise", "Detailed"])
def test_generate_returns_markdown_for_valid_input(style, detail):
"""Valid request returns 200 and markdown from mocked call_llm."""
with patch("app.call_llm") as mock_llm:
mock_llm.return_value = "BEGIN\n SORT list\nEND"
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "Sort a list of numbers",
"style": style,
"detail": detail,
},
)
assert r.status_code == 200
data = r.json()
assert "markdown" in data
assert data["markdown"] == "BEGIN\n SORT list\nEND"
mock_llm.assert_called_once()
def test_generate_returns_502_when_llm_fails():
"""When call_llm raises, endpoint returns 502."""
with patch("app.call_llm") as mock_llm:
mock_llm.side_effect = RuntimeError("API key invalid")
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "Sort a list",
"style": "Academic",
"detail": "Concise",
},
)
assert r.status_code == 502
assert "API key invalid" in r.json().get("detail", "")
def test_generate_request_max_length_12000():
"""Problem description over 12000 chars is rejected by schema."""
with patch("app.call_llm"):
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "x" * 12001,
"style": "Academic",
"detail": "Concise",
},
)
assert r.status_code == 422
def test_free_plan_rejects_input_over_4000_chars():
"""Without X-Plan: premium, input over 4000 chars returns 400."""
with patch("app.call_llm"):
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "x" * 4001,
"style": "Academic",
"detail": "Concise",
},
)
assert r.status_code == 400
assert "4000" in r.json().get("detail", "")
def test_premium_plan_accepts_input_up_to_12000_chars():
"""With user plan premium, input up to 12000 chars is accepted."""
app.dependency_overrides[get_current_user] = _fake_user_premium
try:
with patch("app.call_llm") as mock_llm:
mock_llm.return_value = "BEGIN\nEND"
r = client.post(
"/generate-pseudocode",
json={
"problem_description": "y" * 10000,
"style": "Academic",
"detail": "Concise",
},
)
assert r.status_code == 200
assert r.json().get("markdown") == "BEGIN\nEND"
finally:
app.dependency_overrides[get_current_user] = _fake_user_free
|