#!/usr/bin/env python3 """ Integration test for weekly lives recovery feature. Tests the full flow: 1. Habit has check-ins in previous week 2. Check-in today triggers weekly lives recovery 3. Response includes livesAwarded flag 4. Lives count increases 5. Duplicate awards are prevented """ import sys import os from datetime import datetime, timedelta import json # Add parent directory to path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from habits_helpers import check_and_award_weekly_lives def test_integration_weekly_lives_award(): """Test complete weekly lives recovery flow.""" print("\n=== Testing Weekly Lives Recovery Integration ===\n") today = datetime.now().date() current_week_start = today - timedelta(days=today.weekday()) previous_week_start = current_week_start - timedelta(days=7) # Scenario 1: New habit with check-ins in previous week print("Scenario 1: First award of the week") habit = { "id": "test-habit-1", "name": "Test Habit", "lives": 2, "completions": [ {"date": (previous_week_start + timedelta(days=2)).isoformat(), "type": "check"}, {"date": (previous_week_start + timedelta(days=4)).isoformat(), "type": "check"}, ] } new_lives, was_awarded = check_and_award_weekly_lives(habit) assert was_awarded == True, "Expected life to be awarded" assert new_lives == 3, f"Expected 3 lives, got {new_lives}" print(f"✓ Lives awarded: {habit['lives']} → {new_lives}") print(f"✓ Award flag: {was_awarded}") # Scenario 2: Already awarded this week print("\nScenario 2: Prevent duplicate award") habit['lives'] = new_lives habit['lastLivesAward'] = current_week_start.isoformat() new_lives2, was_awarded2 = check_and_award_weekly_lives(habit) assert was_awarded2 == False, "Expected no duplicate award" assert new_lives2 == 3, f"Lives should remain at 3, got {new_lives2}" print(f"✓ No duplicate award: lives remain at {new_lives2}") # Scenario 3: Only skips in previous week print("\nScenario 3: Skips don't qualify for recovery") habit_with_skips = { "id": "test-habit-2", "name": "Habit with Skips", "lives": 1, "completions": [ {"date": (previous_week_start + timedelta(days=2)).isoformat(), "type": "skip"}, {"date": (previous_week_start + timedelta(days=4)).isoformat(), "type": "skip"}, ] } new_lives3, was_awarded3 = check_and_award_weekly_lives(habit_with_skips) assert was_awarded3 == False, "Skips shouldn't trigger award" assert new_lives3 == 1, f"Lives should remain at 1, got {new_lives3}" print(f"✓ Skips don't count: lives remain at {new_lives3}") # Scenario 4: No cap on lives (can go beyond 3) print("\nScenario 4: Lives can exceed 3") habit_many_lives = { "id": "test-habit-3", "name": "Habit with Many Lives", "lives": 5, "completions": [ {"date": (previous_week_start + timedelta(days=2)).isoformat(), "type": "check"}, ] } new_lives4, was_awarded4 = check_and_award_weekly_lives(habit_many_lives) assert was_awarded4 == True, "Expected life to be awarded" assert new_lives4 == 6, f"Expected 6 lives, got {new_lives4}" print(f"✓ No cap: lives increased from 5 → {new_lives4}") # Scenario 5: No check-ins in previous week print("\nScenario 5: No check-ins = no award") habit_no_checkins = { "id": "test-habit-4", "name": "New Habit", "lives": 2, "completions": [] } new_lives5, was_awarded5 = check_and_award_weekly_lives(habit_no_checkins) assert was_awarded5 == False, "No check-ins = no award" assert new_lives5 == 2, f"Lives should remain at 2, got {new_lives5}" print(f"✓ No previous week check-ins: lives remain at {new_lives5}") print("\n=== All Integration Tests Passed! ===\n") # Print summary of the feature print("Feature Summary:") print("• +1 life awarded per week if habit had ≥1 check-in in previous week") print("• Monday-Sunday week boundaries (ISO 8601)") print("• Award triggers on first check-in of current week") print("• Skips don't count toward recovery") print("• No cap on lives (can accumulate beyond 3)") print("• Prevents duplicate awards in same week") print("") if __name__ == "__main__": try: test_integration_weekly_lives_award() sys.exit(0) except AssertionError as e: print(f"\n✗ Test failed: {e}\n") sys.exit(1) except Exception as e: print(f"\n✗ Unexpected error: {type(e).__name__}: {e}\n") sys.exit(1)