import unittest from datetime import date, datetime, time, timezone from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from app.db.models import Base, FitnessProfile, FoodLog, User from app.daily.metrics import DayMetricsService, plan_hit, signed_balance class DayMetricsTests(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="dm", api_token_hash="x") db.add(user) db.commit() self.user_id = user.id db.add( FitnessProfile( user_id=self.user_id, goal="lose", calorie_target=2000, weight_kg=70, height_cm=175, age=30, ) ) db.commit() def test_signed_balance_uses_tdee_not_calorie_target(self) -> None: tdee = 2500.0 calorie_target = tdee - 500 self.assertEqual(signed_balance({"calories": 2500}, tdee, "lose"), 0) self.assertEqual(signed_balance({"calories": calorie_target}, tdee, "lose"), 500) self.assertEqual(signed_balance({"calories": 2800}, tdee, "gain"), 300) def test_plan_hit_lose(self) -> None: self.assertTrue( plan_hit( {"calories": 1900}, {"calories": 2000}, "lose", has_meals=True, ) ) self.assertFalse( plan_hit( {"calories": 2200}, {"calories": 2000}, "lose", has_meals=True, ) ) def test_metrics_bundle_streaks(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() bundle = DayMetricsService(db, self.user_id).metrics_bundle(d3) self.assertEqual(bundle["meal_log_streak"], 3) self.assertGreaterEqual(bundle["meal_log_best_streak"], 3)