122 lines
3.5 KiB
Python
122 lines
3.5 KiB
Python
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()
|