Files
weirsoe-party-protocol/lobby/tests.py

268 lines
10 KiB
Python

from datetime import timedelta
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from fupogfakta.models import (
Category,
GameSession,
LieAnswer,
Player,
Question,
RoundConfig,
RoundQuestion,
)
User = get_user_model()
class LobbyFlowTests(TestCase):
def setUp(self):
self.host = User.objects.create_user(username="host", password="secret123")
def test_create_session_requires_login(self):
response = self.client.post(reverse("lobby:create_session"))
self.assertEqual(response.status_code, 302)
self.assertEqual(GameSession.objects.count(), 0)
def test_host_can_create_session(self):
self.client.login(username="host", password="secret123")
response = self.client.post(reverse("lobby:create_session"))
self.assertEqual(response.status_code, 201)
body = response.json()
self.assertEqual(body["session"]["status"], GameSession.Status.LOBBY)
self.assertEqual(len(body["session"]["code"]), 6)
session = GameSession.objects.get(code=body["session"]["code"])
self.assertEqual(session.host, self.host)
def test_player_can_join_with_code(self):
session = GameSession.objects.create(host=self.host, code="ABCD23")
response = self.client.post(
reverse("lobby:join_session"),
data={"code": "abcd23", "nickname": "Luna"},
content_type="application/json",
)
self.assertEqual(response.status_code, 201)
body = response.json()
self.assertEqual(body["session"]["code"], "ABCD23")
self.assertEqual(body["player"]["nickname"], "Luna")
self.assertTrue(Player.objects.filter(session=session, nickname="Luna").exists())
def test_join_rejects_duplicate_nickname_case_insensitive(self):
session = GameSession.objects.create(host=self.host, code="QWER12")
Player.objects.create(session=session, nickname="Luna")
response = self.client.post(
reverse("lobby:join_session"),
data={"code": "QWER12", "nickname": "lUna"},
content_type="application/json",
)
self.assertEqual(response.status_code, 409)
self.assertEqual(response.json()["error"], "Nickname already taken")
def test_join_rejects_non_joinable_session(self):
GameSession.objects.create(host=self.host, code="ZXCV98", status=GameSession.Status.FINISHED)
response = self.client.post(
reverse("lobby:join_session"),
data={"code": "ZXCV98", "nickname": "Kai"},
content_type="application/json",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()["error"], "Session is not joinable")
def test_session_detail_returns_players(self):
session = GameSession.objects.create(host=self.host, code="LMNO45")
Player.objects.create(session=session, nickname="Mia", score=7)
Player.objects.create(session=session, nickname="Bo", score=2)
response = self.client.get(reverse("lobby:session_detail", kwargs={"code": "lmno45"}))
self.assertEqual(response.status_code, 200)
payload = response.json()
self.assertEqual(payload["session"]["players_count"], 2)
self.assertEqual([p["nickname"] for p in payload["players"]], ["Bo", "Mia"])
class StartRoundTests(TestCase):
def setUp(self):
self.host = User.objects.create_user(username="host", password="secret123")
self.other_user = User.objects.create_user(username="other", password="secret123")
self.session = GameSession.objects.create(host=self.host, code="ABCD23")
self.category = Category.objects.create(name="Historie", slug="historie", is_active=True)
Question.objects.create(
category=self.category,
prompt="Hvilket år faldt muren?",
correct_answer="1989",
is_active=True,
)
def test_host_can_start_round_with_selected_category(self):
self.client.login(username="host", password="secret123")
response = self.client.post(
reverse("lobby:start_round", kwargs={"code": self.session.code}),
data={"category_slug": self.category.slug},
content_type="application/json",
)
self.assertEqual(response.status_code, 201)
body = response.json()
self.assertEqual(body["session"]["status"], GameSession.Status.LIE)
self.assertEqual(body["round"]["number"], 1)
self.assertEqual(body["round"]["category"]["slug"], self.category.slug)
self.session.refresh_from_db()
self.assertEqual(self.session.status, GameSession.Status.LIE)
round_config = RoundConfig.objects.get(session=self.session, number=1)
self.assertEqual(round_config.category, self.category)
def test_start_round_requires_host(self):
self.client.login(username="other", password="secret123")
response = self.client.post(
reverse("lobby:start_round", kwargs={"code": self.session.code}),
data={"category_slug": self.category.slug},
content_type="application/json",
)
self.assertEqual(response.status_code, 403)
self.assertEqual(response.json()["error"], "Only host can start round")
def test_start_round_requires_existing_active_category_with_questions(self):
self.client.login(username="host", password="secret123")
response = self.client.post(
reverse("lobby:start_round", kwargs={"code": self.session.code}),
data={"category_slug": "ukendt"},
content_type="application/json",
)
self.assertEqual(response.status_code, 404)
empty_category = Category.objects.create(name="Sport", slug="sport", is_active=True)
response = self.client.post(
reverse("lobby:start_round", kwargs={"code": self.session.code}),
data={"category_slug": empty_category.slug},
content_type="application/json",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()["error"], "Category has no active questions")
def test_start_round_rejects_non_lobby_session(self):
self.client.login(username="host", password="secret123")
self.session.status = GameSession.Status.GUESS
self.session.save(update_fields=["status"])
response = self.client.post(
reverse("lobby:start_round", kwargs={"code": self.session.code}),
data={"category_slug": self.category.slug},
content_type="application/json",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()["error"], "Round can only be started from lobby")
class LieSubmissionTests(TestCase):
def setUp(self):
self.host = User.objects.create_user(username="host", password="secret123")
self.session = GameSession.objects.create(host=self.host, code="ABCD23", status=GameSession.Status.LIE)
self.category = Category.objects.create(name="Geografi", slug="geografi", is_active=True)
self.question = Question.objects.create(
category=self.category,
prompt="Hvad er hovedstaden i Australien?",
correct_answer="Canberra",
is_active=True,
)
RoundConfig.objects.create(
session=self.session,
number=1,
category=self.category,
lie_seconds=45,
)
self.player = Player.objects.create(session=self.session, nickname="Luna")
def test_host_can_show_question_and_get_lie_deadline(self):
self.client.login(username="host", password="secret123")
response = self.client.post(reverse("lobby:show_question", kwargs={"code": self.session.code}))
self.assertEqual(response.status_code, 201)
payload = response.json()
self.assertEqual(payload["config"]["lie_seconds"], 45)
self.assertIn("lie_deadline_at", payload["round_question"])
self.assertTrue(RoundQuestion.objects.filter(session=self.session, round_number=1).exists())
def test_player_can_submit_lie_before_deadline(self):
round_question = RoundQuestion.objects.create(
session=self.session,
round_number=1,
question=self.question,
correct_answer=self.question.correct_answer,
)
response = self.client.post(
reverse(
"lobby:submit_lie",
kwargs={"code": self.session.code, "round_question_id": round_question.id},
),
data={"player_id": self.player.id, "text": "Sydney"},
content_type="application/json",
)
self.assertEqual(response.status_code, 201)
self.assertTrue(LieAnswer.objects.filter(round_question=round_question, player=self.player).exists())
def test_submit_lie_rejects_after_time_window(self):
round_question = RoundQuestion.objects.create(
session=self.session,
round_number=1,
question=self.question,
correct_answer=self.question.correct_answer,
)
round_question.shown_at = timezone.now() - timedelta(seconds=46)
round_question.save(update_fields=["shown_at"])
response = self.client.post(
reverse(
"lobby:submit_lie",
kwargs={"code": self.session.code, "round_question_id": round_question.id},
),
data={"player_id": self.player.id, "text": "Melbourne"},
content_type="application/json",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()["error"], "Lie submission window has closed")
def test_submit_lie_rejects_duplicate_submission(self):
round_question = RoundQuestion.objects.create(
session=self.session,
round_number=1,
question=self.question,
correct_answer=self.question.correct_answer,
)
LieAnswer.objects.create(round_question=round_question, player=self.player, text="Perth")
response = self.client.post(
reverse(
"lobby:submit_lie",
kwargs={"code": self.session.code, "round_question_id": round_question.id},
),
data={"player_id": self.player.id, "text": "Brisbane"},
content_type="application/json",
)
self.assertEqual(response.status_code, 409)
self.assertEqual(response.json()["error"], "Lie already submitted for this player")