Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions hanabi/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,94 @@ def test_register(otis):
"hanabi-register", data={"hanab_username": "alice"}, follow=True
)
otis.assert_has(resp, "You already registered")


@pytest.mark.django_db
def test_replay_list(otis):
"""Test viewing the replay list for a contest."""
contest = HanabiContestFactory.create(
pk=42,
variant_name="Rainbow (5 Suits)",
variant_id=15,
start_date=datetime.datetime(2024, 1, 1, tzinfo=UTC),
end_date=datetime.datetime(2024, 1, 14, tzinfo=UTC),
processed=True, # Contest results are processed
)

# Create some replays
HanabiReplayFactory.create(contest=contest, game_score=25, turn_count=40)
HanabiReplayFactory.create(contest=contest, game_score=24, turn_count=42)
HanabiReplayFactory.create(contest=contest, game_score=20, turn_count=35)

# View the replays list
resp = otis.get_20x("hanabi-replays", contest.pk)
assert len(resp.context["replays"]) == 3
assert resp.context["contest"] == contest


@pytest.mark.django_db
def test_replay_list_unprocessed(otis):
"""Test that unprocessed contest results are not visible to non-staff."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))
admin = UserFactory.create(username="admin", is_staff=True, is_superuser=True)

contest = HanabiContestFactory.create(
pk=99,
start_date=datetime.datetime(2024, 1, 1, tzinfo=UTC),
end_date=datetime.datetime(2024, 1, 14, tzinfo=UTC),
processed=False, # Contest not processed yet
)

# Non-staff user cannot view unprocessed results
otis.login(alice)
otis.get_40x("hanabi-replays", contest.pk)

# Staff can view unprocessed results
otis.login(admin)
resp = otis.get_20x("hanabi-replays", contest.pk)
assert resp.context["contest"] == contest


@pytest.mark.django_db
def test_replay_list_with_participation(otis):
"""Test replay list shows own_replay when user participated."""
from hanabi.factories import HanabiParticipationFactory, HanabiPlayerFactory

verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))

contest = HanabiContestFactory.create(
pk=77,
start_date=datetime.datetime(2024, 1, 1, tzinfo=UTC),
end_date=datetime.datetime(2024, 1, 14, tzinfo=UTC),
processed=True,
)

# Create a replay with Alice's participation
player = HanabiPlayerFactory.create(user=alice)
replay = HanabiReplayFactory.create(contest=contest, game_score=22)
HanabiParticipationFactory.create(player=player, replay=replay)

otis.login(alice)
resp = otis.get_20x("hanabi-replays", contest.pk)
assert resp.context["own_replay"] == replay


@pytest.mark.django_db
def test_hanabi_upload(otis):
"""Test the hanabi_upload admin view."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))
admin = UserFactory.create(username="admin", is_staff=True, is_superuser=True)

contest = HanabiContestFactory.create(pk=55)

# Non-admin cannot access
otis.login(alice)
otis.get_40x("hanabi-upload", contest.pk)

# Admin can access (even though it's not implemented)
otis.login(admin)
resp = otis.get_20x("hanabi-upload", contest.pk)
otis.assert_has(resp, "Not implemented")
175 changes: 175 additions & 0 deletions opal/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,178 @@ def test_hint_visibility(otis):
resp = otis.get_20x("opal-show-puzzle", puzzle.hunt.slug, puzzle.slug)
assert "will release" not in resp.content.decode()
assert "use your brain" in resp.content.decode()


@pytest.mark.django_db
def test_leaderboard(otis):
"""Test the leaderboard view (admin only)."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(
username="alice",
first_name="Alice",
last_name="Aardvark",
groups=(verified_group,),
)
bob = UserFactory.create(
username="bob", first_name="Bob", last_name="Beta", groups=(verified_group,)
)
admin = UserFactory.create(username="admin", is_staff=True, is_superuser=True)

hunt = OpalHuntFactory.create(
slug="hunt",
start_date=datetime.datetime(2024, 8, 1, tzinfo=UTC),
)
puzzle1 = OpalPuzzleFactory.create(
hunt=hunt, answer="one", order=1, is_metapuzzle=False
)
puzzle2 = OpalPuzzleFactory.create(
hunt=hunt, answer="two", order=2, is_metapuzzle=False
)
puzzle3 = OpalPuzzleFactory.create(
hunt=hunt, answer="three", order=3, is_metapuzzle=True
)

# Alice solves all puzzles (including meta) after hunt start
with freeze_time("2024-08-15"):
OpalAttemptFactory.create(user=alice, puzzle=puzzle1, guess="one")
OpalAttemptFactory.create(user=alice, puzzle=puzzle2, guess="two")
OpalAttemptFactory.create(user=alice, puzzle=puzzle3, guess="three")

# Bob solves first puzzle only
with freeze_time("2024-08-20"):
OpalAttemptFactory.create(user=bob, puzzle=puzzle1, guess="one")

# Test access control
otis.login(alice)
otis.get_40x("opal-leaderboard", "hunt")

otis.login(admin)
resp = otis.get_20x("opal-leaderboard", "hunt")
otis.assert_has(resp, "Alice Aardvark")
otis.assert_has(resp, "Bob Beta")
assert resp.context["hunt"] == hunt
assert len(resp.context["rows"]) == 2


@pytest.mark.django_db
def test_leaderboard_early_access(otis):
"""Test the leaderboard with early access users (testsolvers)."""
testsolver_group = GroupFactory(name="Testsolver")
testsolver = UserFactory.create(
username="testsolver",
first_name="Test",
last_name="Solver",
groups=(testsolver_group,),
)
admin = UserFactory.create(username="admin", is_staff=True, is_superuser=True)

hunt = OpalHuntFactory.create(
slug="hunt",
start_date=datetime.datetime(2024, 8, 10, tzinfo=UTC),
)
puzzle1 = OpalPuzzleFactory.create(hunt=hunt, answer="one", order=1)

# Testsolver solves before hunt starts (early access)
with freeze_time("2024-08-05"):
OpalAttemptFactory.create(user=testsolver, puzzle=puzzle1, guess="one")

otis.login(admin)
resp = otis.get_20x("opal-leaderboard", "hunt")
rows = resp.context["rows"]
assert len(rows) == 1
assert rows[0]["has_early_access"] is True


@pytest.mark.django_db
def test_person_log(otis):
"""Test the person_log view (admin only)."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))
admin = UserFactory.create(username="admin", is_staff=True, is_superuser=True)

hunt = OpalHuntFactory.create(slug="hunt")
puzzle = OpalPuzzleFactory.create(hunt=hunt, answer="answer")

# Alice makes some attempts
OpalAttemptFactory.create(user=alice, puzzle=puzzle, guess="wrong1")
OpalAttemptFactory.create(user=alice, puzzle=puzzle, guess="wrong2")
OpalAttemptFactory.create(user=alice, puzzle=puzzle, guess="answer")

# Test access control
otis.login(alice)
otis.get_40x("opal-person-log", "hunt", alice.pk)

otis.login(admin)
resp = otis.get_20x("opal-person-log", "hunt", alice.pk)
assert resp.context["hunt"] == hunt
assert resp.context["hunter"] == alice
assert len(resp.context["attempts"]) == 3


@pytest.mark.django_db
def test_finish_page(otis):
"""Test the finish page (after solving a puzzle with achievement)."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))

ach = AchievementFactory.create(diamonds=5)
hunt = OpalHuntFactory.create(slug="hunt")
puzzle = OpalPuzzleFactory.create(
hunt=hunt, slug="final", answer="answer", achievement=ach
)

otis.login(alice)

# Cannot access finish page without solving
otis.get_40x("opal-finish", "hunt", "final")

# Solve the puzzle
OpalAttemptFactory.create(user=alice, puzzle=puzzle, guess="answer")

# Now can access finish page
resp = otis.get_20x("opal-finish", "hunt", "final")
assert resp.context["puzzle"] == puzzle
assert resp.context["achievement"] == ach


@pytest.mark.django_db
def test_finish_page_no_achievement(otis):
"""Test finish page for puzzle without achievement - should be forbidden."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))

hunt = OpalHuntFactory.create(slug="hunt")
puzzle = OpalPuzzleFactory.create(
hunt=hunt, slug="noach", answer="answer", achievement=None
)

otis.login(alice)
OpalAttemptFactory.create(user=alice, puzzle=puzzle, guess="answer")

# Should be forbidden since puzzle has no achievement
otis.get_40x("opal-finish", "hunt", "noach")


@pytest.mark.django_db
def test_close_answer(otis):
"""Test submitting a close answer."""
verified_group = GroupFactory(name="Verified")
alice = UserFactory.create(username="alice", groups=(verified_group,))

hunt = OpalHuntFactory.create(slug="hunt")
OpalPuzzleFactory.create(
hunt=hunt,
slug="puzzle",
answer="CORRECT",
partial_answers="CORRELATION\nALMOSTCORRECT",
)

otis.login(alice)
resp = otis.post_20x(
"opal-show-puzzle",
"hunt",
"puzzle",
data={"guess": "CORRELATION"},
follow=True,
)
otis.assert_has(resp, "Keep going")
13 changes: 12 additions & 1 deletion tubes/factories.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from factory.declarations import SubFactory
from factory.django import DjangoModelFactory
from factory.faker import Faker

from .models import Tube
from .models import JoinRecord, Tube


class TubeFactory(DjangoModelFactory):
Expand All @@ -12,3 +13,13 @@ class Meta:
description = Faker("paragraph")
status = "TB_ACTIVE"
main_url = Faker("url")


class JoinRecordFactory(DjangoModelFactory):
class Meta:
model = JoinRecord

tube = SubFactory(TubeFactory)
user = None
activation_time = None
invite_url = Faker("url")
Loading