import pytest from rest_framework.exceptions import ValidationError from accounts.models import User from contest.game_services import ( SUDOKU_PUZZLES, request_sudoku_hint, start_game, submit_game, ) from contest.models import MathGameAttempt @pytest.fixture def game_user(db): return User.objects.create_user( username="game_user", password="StrongPass_2026", nickname="游戏玩家", ) @pytest.mark.django_db def test_twenty_four_服务端校验数字使用与幂等提交(game_user): attempt = MathGameAttempt.objects.create( user=game_user, kind=MathGameAttempt.Kind.TWENTY_FOUR, puzzle={"numbers": [1, 3, 4, 6]}, solution={"target": 24}, ) result = submit_game( game_user, attempt.id, {"expression": "6 / (1 - 3 / 4)"}, "game-submit-1", ) replay = submit_game( game_user, attempt.id, {"expression": "1 + 3 + 4 + 6"}, "game-submit-1", ) assert result["status"] == MathGameAttempt.Status.COMPLETED assert result["score"] >= 100 assert replay["score"] == result["score"] @pytest.mark.django_db def test_twenty_four_拒绝额外数字和非四则表达式(game_user): attempt = MathGameAttempt.objects.create( user=game_user, kind=MathGameAttempt.Kind.TWENTY_FOUR, puzzle={"numbers": [1, 3, 4, 6]}, solution={"target": 24}, ) with pytest.raises(ValidationError, match="四个数字"): submit_game( game_user, attempt.id, {"expression": "6 / (1 - 3 / 4) + 24 - 24"}, "invalid-extra-number", ) with pytest.raises(ValidationError, match="只允许"): submit_game( game_user, attempt.id, {"expression": "pow(2, 3) * 3"}, "invalid-function", ) @pytest.mark.django_db def test_sudoku_提示受限并由服务端校验完整答案(game_user): payload = start_game( game_user, MathGameAttempt.Kind.SUDOKU, MathGameAttempt.Difficulty.EASY, ) attempt = MathGameAttempt.objects.get(id=payload["attempt_id"]) hint = request_sudoku_hint(game_user, attempt.id) solution_text = SUDOKU_PUZZLES[MathGameAttempt.Difficulty.EASY][0][1] solution = [ [int(solution_text[row * 9 + column]) for column in range(9)] for row in range(9) ] result = submit_game( game_user, attempt.id, {"grid": solution}, "sudoku-submit-1", ) assert hint["value"] == solution[hint["row"]][hint["column"]] assert result["status"] == MathGameAttempt.Status.COMPLETED assert result["hints_used"] == 1 @pytest.mark.django_db def test_math_game_api_目录公开但开局需要登录(client, game_user): catalog = client.get("/api/v1/contests/games/") anonymous_start = client.post( "/api/v1/contests/games/twenty_four/start/", {"difficulty": "easy"}, content_type="application/json", ) client.force_login(game_user) authenticated_start = client.post( "/api/v1/contests/games/twenty_four/start/", {"difficulty": "easy"}, content_type="application/json", ) assert catalog.status_code == 200 assert {item["kind"] for item in catalog.json()} == {"sudoku", "twenty_four"} assert anonymous_start.status_code in {401, 403} assert authenticated_start.status_code == 201 assert "solution" not in authenticated_start.json()