from __future__ import annotations from fastapi.testclient import TestClient from tests.conftest import create_onboarded_student def test_zero_to_forty_question_limit_and_mixed_grading(client: TestClient) -> None: token_a, _ = create_onboarded_student(client, "author_owl", "owl", "avatar-2") headers_a = {"Authorization": f"Bearer {token_a}"} # 0 questions is valid on free tier zero_resp = client.post( "/api/v1/quizzes", headers=headers_a, json={ "title": "Draft Empty Quiz", "description": "Zero questions allowed", "is_public": True, "questions": [], }, ) assert zero_resp.status_code == 201 assert zero_resp.json()["question_count"] == 0 assert zero_resp.json()["quiz_mode"] == "empty" # 41 questions is rejected on free tier too_many = [ { "question_type": "write_in", "prompt": f"Question {i}", "correct_answer": str(i), } for i in range(41) ] over_limit = client.post( "/api/v1/quizzes", headers=headers_a, json={"title": "41 Questions", "is_public": True, "questions": too_many}, ) assert over_limit.status_code == 422 # Create mixed Multiple-Choice + Write-In quiz quiz_resp = client.post( "/api/v1/quizzes", headers=headers_a, json={ "title": "Science Sprint", "description": "Test MC and write-in", "is_public": True, "questions": [ { "question_type": "multiple_choice", "prompt": "What is H2O?", "options": [ {"id": "a", "text": "Water"}, {"id": "b", "text": "Helium"}, ], "correct_answer": "a", }, { "question_type": "write_in", "prompt": "How many planets orbit the Sun?", "correct_answer": "8", "accepted_answers": ["eight"], }, ], }, ) assert quiz_resp.status_code == 201 quiz = quiz_resp.json() quiz_id = quiz["id"] share_slug = quiz["share_slug"] q1_id = str(quiz["questions"][0]["id"]) q2_id = str(quiz["questions"][1]["id"]) # Fetch via share_slug as unauthenticated visitor (clear session cookie first) client.cookies.clear() by_slug = client.get(f"/api/v1/quizzes/{share_slug}") assert by_slug.status_code == 200 assert by_slug.json()["editable_questions"] is None # Player B plays twice: first 100%, then 50% -> latest is 50%, all-time best stays 100%! token_b, _ = create_onboarded_student(client, "speedy_otter", "otter", "avatar-4") headers_b = {"Authorization": f"Bearer {token_b}"} sub1 = client.post( f"/api/v1/quizzes/{quiz_id}/submit", headers=headers_b, json={"answers": {q1_id: "a", q2_id: " EIGHT "}}, ) assert sub1.status_code == 200 assert sub1.json()["score_percent"] == 100.0 sub2 = client.post( f"/api/v1/quizzes/{quiz_id}/submit", headers=headers_b, json={"answers": {q1_id: "a", q2_id: "nine"}}, ) assert sub2.status_code == 200 s2 = sub2.json() assert s2["my_latest_score"]["score_percent"] == 50.0 assert s2["my_best_score"]["score_percent"] == 100.0 assert s2["global_best_score"]["score_percent"] == 100.0 assert s2["global_best_score"]["holder_nickname"] == "speedy_otter" # Thumbs up and down voting v_up = client.post(f"/api/v1/quizzes/{quiz_id}/vote", headers=headers_a, json={"value": 1}) assert v_up.status_code == 200 v_down = client.post(f"/api/v1/quizzes/{quiz_id}/vote", headers=headers_b, json={"value": -1}) assert v_down.status_code == 200 assert v_down.json()["upvotes"] == 1 assert v_down.json()["downvotes"] == 1