crowncode-backend / tests /test_dreams.py
Rthur2003's picture
feat: remix engine routes dream analysis servisleri ve dataset organization utilities eklendi
e49c006
Raw History Blame Contribute Delete
4.48 kB
"""Tests for /api/dreams/analyze endpoint."""
from __future__ import annotations
import json
from unittest.mock import MagicMock, patch
import pytest
from fastapi.testclient import TestClient
from app.routes.dreams import _rate_store
@pytest.fixture(autouse=True)
def _reset_rate_limiter():
_rate_store.clear()
yield
_rate_store.clear()
def _mock_gemini_response(**overrides: object) -> MagicMock:
defaults = {
"emotions": ["fear", "wonder"],
"themes": ["being chased"],
"symbols": ["water"],
"interpretation": "This reflects anxiety about a real-life situation.",
"lucidityIndicator": False,
}
defaults.update(overrides)
response = MagicMock()
response.text = json.dumps(defaults)
return response
def test_analyze_valid_dream_returns_structured_result(client: TestClient) -> None:
mock_client = MagicMock()
mock_client.models.generate_content.return_value = _mock_gemini_response()
with patch("app.services.dream_analyzer._get_client", return_value=mock_client):
response = client.post(
"/api/dreams/analyze",
json={"dreamText": "I was being chased through a dark forest and found a river.", "language": "English"},
)
assert response.status_code == 200
body = response.json()
assert body["emotions"] == ["fear", "wonder"]
assert body["themes"] == ["being chased"]
assert body["lucidityIndicator"] is False
def test_analyze_rejects_too_short_dream(client: TestClient) -> None:
response = client.post("/api/dreams/analyze", json={"dreamText": "hi"})
assert response.status_code == 400
assert response.json()["detail"]["code"] == "dream_too_short"
def test_analyze_rejects_empty_dream_text(client: TestClient) -> None:
response = client.post("/api/dreams/analyze", json={"dreamText": ""})
assert response.status_code == 422
def test_analyze_rejects_missing_dream_text(client: TestClient) -> None:
response = client.post("/api/dreams/analyze", json={})
assert response.status_code == 422
def test_analyze_handles_missing_api_key(client: TestClient) -> None:
with patch("app.services.dream_analyzer._get_client", side_effect=ValueError("DREAMS_GEMINI_API_KEY required")):
response = client.post(
"/api/dreams/analyze",
json={"dreamText": "A perfectly normal dream about flying over mountains."},
)
assert response.status_code == 503
assert response.json()["detail"]["code"] == "service_not_configured"
def test_analyze_handles_malformed_gemini_output(client: TestClient) -> None:
mock_client = MagicMock()
bad_response = MagicMock()
bad_response.text = "I refuse to analyze this."
mock_client.models.generate_content.return_value = bad_response
with patch("app.services.dream_analyzer._get_client", return_value=mock_client):
response = client.post(
"/api/dreams/analyze",
json={"dreamText": "A perfectly normal dream about flying over mountains."},
)
assert response.status_code == 502
assert response.json()["detail"]["code"] == "analysis_failed"
def test_analyze_filters_invalid_emotions_from_gemini(client: TestClient) -> None:
"""Gemini could hallucinate an emotion outside the allowed set — the
service must filter it rather than pass it straight through."""
mock_client = MagicMock()
mock_client.models.generate_content.return_value = _mock_gemini_response(
emotions=["fear", "not_a_real_emotion", "joy"]
)
with patch("app.services.dream_analyzer._get_client", return_value=mock_client):
response = client.post(
"/api/dreams/analyze",
json={"dreamText": "A perfectly normal dream about flying over mountains."},
)
assert response.status_code == 200
assert "not_a_real_emotion" not in response.json()["emotions"]
def test_analyze_enforces_rate_limit(client: TestClient) -> None:
mock_client = MagicMock()
mock_client.models.generate_content.return_value = _mock_gemini_response()
with patch("app.services.dream_analyzer._get_client", return_value=mock_client):
last_status = 200
for _ in range(10):
r = client.post(
"/api/dreams/analyze",
json={"dreamText": "A perfectly normal dream about flying over mountains."},
)
last_status = r.status_code
assert last_status == 429