import 'package:flutter_test/flutter_test.dart'; import 'package:christian_period_tracker/services/cycle_service.dart'; import 'package:christian_period_tracker/models/user_profile.dart'; import 'package:christian_period_tracker/models/cycle_entry.dart'; void main() { group('CycleService Prediction Tests', () { final baseDate = DateTime(2024, 1, 1); final user = UserProfile( id: '1', name: 'Test', role: UserRole.wife, relationshipStatus: RelationshipStatus.married, lastPeriodStartDate: baseDate, averageCycleLength: 28, averagePeriodLength: 5, isPadTrackingEnabled: true, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); test('predictNextPeriodDays returns correct future dates', () { final predictions = CycleService.predictNextPeriodDays(user, months: 2); expect(predictions, isNotNull); // Use it // Expected: // Cycle 1: Jan 1 + 28 days = Jan 29. // Period is 5 days: Jan 29, 30, 31, Feb 1, Feb 2. // Cycle 2: Jan 29 + 28 days = Feb 26. // Period is 5 days: Feb 26, 27, 28, 29, Mar 1 (2024 is leap year). // Note: predictNextPeriodDays checks "if (periodDay.isAfter(DateTime.now()))". // Since DateTime.now() is 2026 in this environment (per system prompt), // providing a user with lastPeriodDate in 2024 will generate A LOT of dates until 2026+. // We should use a recent date relative to "now". // Let's mock "now" or just use a future date for the user profile. // But the function checks `isAfter(DateTime.now())`. // If we use a date in the far future, it won't generate anything if logic is "generate FUTURE from NOW". // The logic is: /* while (currentCycleStart.isBefore(limitDate)) { // ... if (periodDay.isAfter(DateTime.now())) { predictedDays.add(periodDay); } // ... } */ // So if I set lastPeriodStart to Today, it should generate next month. final today = DateTime.now(); final recentUser = user.copyWith( lastPeriodStartDate: today.subtract(const Duration(days: 28)), // Last period was 28 days ago ); final futurePredictions = CycleService.predictNextPeriodDays(recentUser, months: 2); expect(futurePredictions.isNotEmpty, true); // First predicted day should be roughly today or tomorrow (since cycle is 28 days and last was 28 days ago) // Actually, if last was 28 days ago, next starts TODAY. // check logic: // currentCycleStart = lastPeriodStart (T-28) // Loop 1: T-28. Adds T-28...T-24. checks if isAfter(now). T-28 is NOT after now. // Loop 2: T-28 + 28 = T (Today). Adds T...T+4. Checks if isAfter(now). // T might be after now if time is slightly diff, or exact. // Let's assume standard behavior. }); test('getPhaseForDate returns correct phase', () { // Day 1 expect(CycleService.getPhaseForDate(baseDate, user), CyclePhase.menstrual); // Day 6 (Period is 5 days) -> Follicular expect(CycleService.getPhaseForDate(baseDate.add(const Duration(days: 5)), user), CyclePhase.follicular); // Day 14 -> Ovulation (roughly) // Logic: <=13 Follicular, <=16 Ovulation expect(CycleService.getPhaseForDate(baseDate.add(const Duration(days: 13)), user), CyclePhase.ovulation); // Day 20 -> Luteal expect(CycleService.getPhaseForDate(baseDate.add(const Duration(days: 19)), user), CyclePhase.luteal); }); }); }