volsu-contests/backend/tests/test_problems.py
2025-11-30 19:55:50 +03:00

250 lines
8.3 KiB
Python

import pytest
from httpx import AsyncClient
from app.models.contest import Contest
from app.models.problem import Problem
from app.models.test_case import TestCase
class TestListProblems:
"""Tests for listing problems by contest."""
async def test_list_problems_empty(
self, client: AsyncClient, auth_headers: dict, test_contest: Contest
):
"""Test listing problems when none exist."""
response = await client.get(
f"/api/problems/contest/{test_contest.id}", headers=auth_headers
)
assert response.status_code == 200
assert response.json() == []
async def test_list_problems_with_data(
self,
client: AsyncClient,
auth_headers: dict,
test_contest: Contest,
test_problem: Problem,
):
"""Test listing problems with existing data."""
response = await client.get(
f"/api/problems/contest/{test_contest.id}", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert len(data) == 1
assert data[0]["title"] == test_problem.title
class TestGetProblem:
"""Tests for getting a single problem."""
async def test_get_problem_success(
self, client: AsyncClient, auth_headers: dict, test_problem: Problem
):
"""Test getting an existing problem."""
response = await client.get(
f"/api/problems/{test_problem.id}", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert data["id"] == test_problem.id
assert data["title"] == test_problem.title
assert data["description"] == test_problem.description
async def test_get_problem_not_found(self, client: AsyncClient, auth_headers: dict):
"""Test getting a non-existent problem."""
response = await client.get("/api/problems/99999", headers=auth_headers)
assert response.status_code == 404
async def test_get_problem_includes_sample_tests(
self,
client: AsyncClient,
auth_headers: dict,
test_problem: Problem,
test_cases: list[TestCase],
):
"""Test that getting a problem includes sample tests."""
response = await client.get(
f"/api/problems/{test_problem.id}", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
# Should include sample tests
assert "sample_tests" in data
# Only sample tests should be visible (is_sample=True)
sample_count = sum(1 for tc in test_cases if tc.is_sample)
assert len(data["sample_tests"]) == sample_count
class TestCreateProblem:
"""Tests for creating problems."""
async def test_create_problem_as_admin(
self, client: AsyncClient, admin_headers: dict, test_contest: Contest
):
"""Test creating a problem as admin."""
response = await client.post(
"/api/problems/",
headers=admin_headers,
json={
"contest_id": test_contest.id,
"title": "New Problem",
"description": "Solve this problem",
"input_format": "One integer n",
"output_format": "One integer",
"constraints": "1 <= n <= 100",
"time_limit_ms": 2000,
"memory_limit_kb": 131072,
"total_points": 50,
},
)
assert response.status_code == 201
data = response.json()
assert data["title"] == "New Problem"
assert data["total_points"] == 50
async def test_create_problem_as_participant(
self, client: AsyncClient, auth_headers: dict, test_contest: Contest
):
"""Test that participants cannot create problems."""
response = await client.post(
"/api/problems/",
headers=auth_headers,
json={
"contest_id": test_contest.id,
"title": "New Problem",
"description": "Solve this problem",
},
)
assert response.status_code == 403
async def test_create_problem_with_test_cases(
self, client: AsyncClient, admin_headers: dict, test_contest: Contest
):
"""Test creating a problem with test cases."""
response = await client.post(
"/api/problems/",
headers=admin_headers,
json={
"contest_id": test_contest.id,
"title": "Problem with Tests",
"description": "A problem with test cases",
"test_cases": [
{
"input": "1 2",
"expected_output": "3",
"is_sample": True,
"points": 25,
},
{
"input": "5 5",
"expected_output": "10",
"is_sample": False,
"points": 75,
},
],
},
)
assert response.status_code == 201
data = response.json()
assert len(data["sample_tests"]) == 1 # Only sample tests in response
class TestUpdateProblem:
"""Tests for updating problems."""
async def test_update_problem_as_admin(
self, client: AsyncClient, admin_headers: dict, test_problem: Problem
):
"""Test updating a problem as admin."""
response = await client.put(
f"/api/problems/{test_problem.id}",
headers=admin_headers,
json={"title": "Updated Problem Title"},
)
assert response.status_code == 200
data = response.json()
assert data["title"] == "Updated Problem Title"
async def test_update_problem_as_participant(
self, client: AsyncClient, auth_headers: dict, test_problem: Problem
):
"""Test that participants cannot update problems."""
response = await client.put(
f"/api/problems/{test_problem.id}",
headers=auth_headers,
json={"title": "Updated Title"},
)
assert response.status_code == 403
class TestDeleteProblem:
"""Tests for deleting problems."""
async def test_delete_problem_as_admin(
self, client: AsyncClient, admin_headers: dict, test_problem: Problem
):
"""Test deleting a problem as admin."""
response = await client.delete(
f"/api/problems/{test_problem.id}", headers=admin_headers
)
assert response.status_code == 204
# Verify it's deleted
response = await client.get(
f"/api/problems/{test_problem.id}", headers=admin_headers
)
assert response.status_code == 404
class TestTestCases:
"""Tests for test case management."""
async def test_get_test_cases_as_admin(
self,
client: AsyncClient,
admin_headers: dict,
test_problem: Problem,
test_cases: list[TestCase],
):
"""Test getting all test cases as admin."""
response = await client.get(
f"/api/problems/{test_problem.id}/test-cases", headers=admin_headers
)
assert response.status_code == 200
data = response.json()
assert len(data) == len(test_cases)
async def test_add_test_case_as_admin(
self, client: AsyncClient, admin_headers: dict, test_problem: Problem
):
"""Test adding a test case as admin."""
response = await client.post(
f"/api/problems/{test_problem.id}/test-cases",
headers=admin_headers,
json={
"input": "10 20",
"expected_output": "30",
"is_sample": True,
"points": 25,
},
)
assert response.status_code == 201
data = response.json()
assert data["input"] == "10 20"
assert data["expected_output"] == "30"
async def test_delete_test_case_as_admin(
self,
client: AsyncClient,
admin_headers: dict,
test_cases: list[TestCase],
):
"""Test deleting a test case as admin."""
test_case = test_cases[0]
response = await client.delete(
f"/api/problems/test-cases/{test_case.id}", headers=admin_headers
)
assert response.status_code == 204