Files
tipibot/tests/test_quests.py
Rene Arumetsa 83a60cda55
Some checks failed
Test & Deploy / test (push) Has been cancelled
Test & Deploy / deploy (push) Has been cancelled
Refator eco code. Split into modules
2026-07-27 00:49:34 +03:00

123 lines
4.7 KiB
Python

"""Tests for the quest system: rotation, progress, claiming, schema detection."""
import logging
from datetime import datetime, timedelta, timezone
from core import economy
from conftest import run
UID = 111
def _fixed_now(monkeypatch, dt: datetime):
monkeypatch.setattr(economy.store, "_clock", lambda: dt)
return dt
def _complete_all_active_quests(fake_pb, user_id: int) -> tuple[int, int]:
"""Push every active quest's tracked counter past its goal directly in the
store. Returns (expected_coins, expected_exp)."""
rec = fake_pb.record_for(user_id)
coins = exp = 0
for pool, block in (
(economy.QUESTS_DAILY, rec["quest_daily"]),
(economy.QUESTS_WEEKLY, rec["quest_weekly"]),
):
for qid, state in block["quests"].items():
stat = pool[qid]["stat"]
rec[stat] = state["snap"] + pool[qid]["goal"]
coins += pool[qid]["coins"]
exp += pool[qid]["exp"]
return coins, exp
class TestRotation:
def test_deterministic_per_seed(self):
a = economy._pick_quests(economy.QUESTS_DAILY, 3, "1:date:2026-07-26")
b = economy._pick_quests(economy.QUESTS_DAILY, 3, "1:date:2026-07-26")
assert a == b
def test_users_get_different_sets(self):
sets = {
tuple(economy._pick_quests(economy.QUESTS_DAILY, 3, f"{uid}:date:2026-07-26"))
for uid in range(50)
}
assert len(sets) > 1
def test_counts(self, fake_pb):
data = run(economy.get_quests(UID))
assert len(data["daily"]) == economy.DAILY_QUEST_COUNT
assert len(data["weekly"]) == economy.WEEKLY_QUEST_COUNT
def test_daily_rolls_over_weekly_stays(self, fake_pb, monkeypatch):
# a Tuesday, so day+1 stays inside the same ISO week
t0 = _fixed_now(monkeypatch, datetime(2026, 7, 21, 12, tzinfo=timezone.utc))
run(economy.get_quests(UID))
rec = fake_pb.record_for(UID)
daily_before, weekly_before = dict(rec["quest_daily"]), dict(rec["quest_weekly"])
_fixed_now(monkeypatch, t0 + timedelta(days=1))
run(economy.get_quests(UID))
rec = fake_pb.record_for(UID)
assert rec["quest_daily"]["date"] != daily_before["date"]
assert rec["quest_weekly"] == weekly_before
class TestProgress:
def test_progress_tracks_counter_delta(self, fake_pb):
run(economy.get_quests(UID))
rec = fake_pb.record_for(UID)
qid, state = next(iter(rec["quest_daily"]["quests"].items()))
stat = economy.QUESTS_DAILY[qid]["stat"]
rec[stat] = state["snap"] + 1
data = run(economy.get_quests(UID))
quest = next(q for q in data["daily"] if q["id"] == qid)
assert quest["progress"] == 1
def test_pre_roll_stats_do_not_count(self, fake_pb):
run(economy.get_user(UID))
fake_pb.record_for(UID)["work_count"] = 500
data = run(economy.get_quests(UID))
assert all(q["progress"] == 0 for q in data["daily"] + data["weekly"])
class TestClaim:
def test_claim_pays_and_is_idempotent(self, fake_pb):
run(economy.get_quests(UID))
coins, exp = _complete_all_active_quests(fake_pb, UID)
res = run(economy.claim_quests(UID))
assert res["ok"]
assert res["claimed"] == economy.DAILY_QUEST_COUNT + economy.WEEKLY_QUEST_COUNT
assert res["coins"] == coins and res["exp"] == exp
assert fake_pb.record_for(UID)["balance"] == coins
res = run(economy.claim_quests(UID))
assert not res["ok"] and res["reason"] == "nothing"
def test_claim_with_nothing_done(self, fake_pb):
run(economy.get_quests(UID))
res = run(economy.claim_quests(UID))
assert not res["ok"]
class TestSchemaDetection:
def test_missing_fields_reported(self, fake_pb_without_quest_fields):
assert run(economy.missing_schema_fields()) == ["quest_daily", "quest_weekly"]
def test_healthy_schema_reports_nothing(self, fake_pb):
assert run(economy.missing_schema_fields()) == []
def test_missing_quest_fields_warn_and_zero_progress(
self, fake_pb_without_quest_fields, caplog
):
"""Reproduces the live 'quests never progress' symptom: when the
collection schema lacks quest_daily/quest_weekly, PocketBase drops the
rolled quest block, so every call re-rolls with a fresh snapshot."""
fake = fake_pb_without_quest_fields
with caplog.at_level(logging.WARNING):
run(economy.get_quests(UID))
assert any("quest fields" in r.message for r in caplog.records)
# counters advance, but progress stays 0 because the snapshot re-rolls
fake.record_for(UID)["work_count"] = 500
data = run(economy.get_quests(UID))
assert all(q["progress"] == 0 for q in data["daily"] + data["weekly"])