import unittest from datetime import date, datetime, time, timedelta, timezone from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from app.db.models import Base, FitnessProfile, FoodLog, User, WorkoutLog from app.fitness.gamification import _plan_hit, build_gamification class GamificationTests(unittest.TestCase): def setUp(self) -> None: self.engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(self.engine) self.Session = sessionmaker(bind=self.engine) with Session(self.engine) as db: user = User(username="g1", api_token_hash="x") db.add(user) db.commit() self.user_id = user.id db.add( FitnessProfile( user_id=self.user_id, goal="lose", weekly_workouts=3, calorie_target=2000, ) ) db.commit() def test_plan_hit_lose_goal(self) -> None: summary = { "meals": [{"id": 1}], "totals": {"calories": 1900}, "targets": {"calories": 2000}, } self.assertTrue(_plan_hit(summary, "lose")) summary["totals"]["calories"] = 2200 self.assertFalse(_plan_hit(summary, "lose")) def test_meal_streak_and_medals(self) -> None: d1 = date(2026, 6, 16) d2 = date(2026, 6, 17) d3 = date(2026, 6, 18) with Session(self.engine) as db: for d in (d1, d2, d3): db.add( FoodLog( user_id=self.user_id, description="meal", calories=1800, logged_at=datetime.combine(d, time(12), tzinfo=timezone.utc), ) ) db.commit() result = build_gamification(db, self.user_id, end_day=d3) self.assertEqual(result["streaks"]["meal_log"], 3) meal_medal = next(m for m in result["medals"] if m["id"] == "meal_streak_3") self.assertTrue(meal_medal["earned"]) def test_workout_week_goal_uses_profile(self) -> None: d = date(2026, 6, 18) with Session(self.engine) as db: for i in range(3): db.add( WorkoutLog( user_id=self.user_id, title=f"w{i}", duration_min=30, logged_at=datetime.combine( d - timedelta(days=i), time(10), tzinfo=timezone.utc, ), ) ) db.commit() result = build_gamification(db, self.user_id, end_day=d) medal = next(m for m in result["medals"] if m["id"] == "workout_week_goal") self.assertTrue(medal["earned"]) self.assertEqual(result["workouts"]["weekly_target"], 3)