"""Tests für GET /me/entitlements Zusammenstellung.""" from datetime import datetime, timezone from entitlements import _serialize_reset_at, build_me_entitlements from tenant_context import TenantContext def test_serialize_reset_at(): dt = datetime(2026, 7, 1, tzinfo=timezone.utc) assert _serialize_reset_at(dt) == "2026-07-01T00:00:00+00:00" assert _serialize_reset_at(None) is None def test_build_me_entitlements_no_club(monkeypatch): monkeypatch.setattr( "entitlements.resolve_capabilities_map", lambda cur, tenant, club_id=None: {"exercises.read": False}, ) tenant = TenantContext( profile_id=1, global_role="user", effective_club_id=None, club_ids=frozenset(), memberships=[], account_state="verified_pending_club", ) out = build_me_entitlements(object(), tenant) assert out["account_state"] == "verified_pending_club" assert out["club_id"] is None assert out["features"] == {} assert out["capabilities"]["exercises.read"] is False def test_build_me_entitlements_with_club(monkeypatch): monkeypatch.setattr( "entitlements.resolve_capabilities_map", lambda cur, tenant, club_id=None: { "exercises.read": True, "exercises.ai.suggest": True, }, ) monkeypatch.setattr( "entitlements.club_features_map", lambda cur, club_id, conn=None: { "plan_id": "free", "club_id": club_id, "features": { "ai_calls": { "allowed": False, "used": 0, "limit": 0, "remaining": 0, "reason": "feature_disabled", "reset_at": None, } }, }, ) monkeypatch.setattr("entitlements._club_exists", lambda cur, cid: True) monkeypatch.setattr( "entitlements.is_club_feature_quota_bypassed", lambda *a, **k: False, ) tenant = TenantContext( profile_id=3, global_role="trainer", effective_club_id=1, club_ids=frozenset({1}), memberships=[{"id": 1, "roles": ["trainer"]}], account_state="active_member", ) out = build_me_entitlements(object(), tenant, club_id=1) assert out["club_id"] == 1 assert out["plan_id"] == "free" assert out["club_roles"] == ["trainer"] assert out["features"]["ai_calls"]["limit"] == 0 assert out["capabilities"]["exercises.ai.suggest"] is True