from typing import Any from httpx import AsyncClient from sqlalchemy.ext.asyncio import AsyncSession from src.models import Category, Difficulty, Explanation, Pattern, Question, Solution SampleData = dict[str, Any] async def create_sample_data(db_session: AsyncSession) -> SampleData: category = Category(name="Arrays", slug="arrays", description="Array problems") db_session.add(category) pattern = Pattern( name="Two Pointers", slug="two-pointers", description="Two pointer technique", ) db_session.add(pattern) await db_session.flush() question = Question( title="Two Sum", slug="two-sum", difficulty=Difficulty.EASY, description="Find two numbers that add up to target.", leetcode_id=1, leetcode_url="https://leetcode.com/problems/two-sum/", ) question.categories = [category] question.patterns = [pattern] db_session.add(question) await db_session.flush() explanation = Explanation( question_id=question.id, approach="Use a hash map.", intuition="Store seen values for O(1) lookup.", time_complexity="O(n)", space_complexity="O(n)", ) db_session.add(explanation) solution = Solution( question_id=question.id, approach_name="Hash Map", code="def two_sum(nums, target): pass", is_optimal=True, ) db_session.add(solution) await db_session.commit() return {"question": question, "category": category, "pattern": pattern} async def test_health_check(client: AsyncClient) -> None: response = await client.get("/api/health") assert response.status_code == 200 assert response.json() == {"status": "healthy"} async def test_list_questions_empty(client: AsyncClient) -> None: response = await client.get("/api/questions") assert response.status_code == 200 data = response.json() assert data["items"] == [] assert data["total"] == 0 async def test_list_questions(client: AsyncClient, db_session: AsyncSession) -> None: await create_sample_data(db_session) response = await client.get("/api/questions") assert response.status_code == 200 data = response.json() assert data["total"] == 1 assert len(data["items"]) == 1 assert data["items"][0]["title"] == "Two Sum" assert data["items"][0]["difficulty"] == "easy" async def test_list_questions_filter_difficulty( client: AsyncClient, db_session: AsyncSession ) -> None: await create_sample_data(db_session) response = await client.get("/api/questions?difficulty=easy") assert response.status_code == 200 assert response.json()["total"] == 1 response = await client.get("/api/questions?difficulty=hard") assert response.status_code == 200 assert response.json()["total"] == 0 async def test_list_questions_invalid_difficulty(client: AsyncClient) -> None: response = await client.get("/api/questions?difficulty=invalid") assert response.status_code == 400 async def test_get_question(client: AsyncClient, db_session: AsyncSession) -> None: await create_sample_data(db_session) response = await client.get("/api/questions/two-sum") assert response.status_code == 200 data = response.json() assert data["title"] == "Two Sum" assert data["explanation"]["time_complexity"] == "O(n)" assert len(data["solutions"]) == 1 async def test_get_question_not_found(client: AsyncClient) -> None: response = await client.get("/api/questions/nonexistent") assert response.status_code == 404 async def test_list_categories_empty(client: AsyncClient) -> None: response = await client.get("/api/categories") assert response.status_code == 200 assert response.json()["items"] == [] async def test_list_categories(client: AsyncClient, db_session: AsyncSession) -> None: await create_sample_data(db_session) response = await client.get("/api/categories") assert response.status_code == 200 data = response.json() assert len(data["items"]) == 1 assert data["items"][0]["name"] == "Arrays" assert data["items"][0]["question_count"] == 1 async def test_list_patterns_empty(client: AsyncClient) -> None: response = await client.get("/api/patterns") assert response.status_code == 200 assert response.json()["items"] == [] async def test_list_patterns(client: AsyncClient, db_session: AsyncSession) -> None: await create_sample_data(db_session) response = await client.get("/api/patterns") assert response.status_code == 200 data = response.json() assert len(data["items"]) == 1 assert data["items"][0]["name"] == "Two Pointers" async def test_get_pattern(client: AsyncClient, db_session: AsyncSession) -> None: await create_sample_data(db_session) response = await client.get("/api/patterns/two-pointers") assert response.status_code == 200 data = response.json() assert data["name"] == "Two Pointers" assert data["question_count"] == 1 async def test_get_pattern_not_found(client: AsyncClient) -> None: response = await client.get("/api/patterns/nonexistent") assert response.status_code == 404 async def test_get_stats_empty(client: AsyncClient) -> None: response = await client.get("/api/stats") assert response.status_code == 200 data = response.json() assert data["total_questions"] == 0 assert data["by_difficulty"]["easy"] == 0 async def test_get_stats(client: AsyncClient, db_session: AsyncSession) -> None: await create_sample_data(db_session) response = await client.get("/api/stats") assert response.status_code == 200 data = response.json() assert data["total_questions"] == 1 assert data["by_difficulty"]["easy"] == 1 assert len(data["by_category"]) == 1 assert len(data["by_pattern"]) == 1