250 lines
8.3 KiB
Python
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
|