import 'dart:developer' as dev; import 'package:flutter_test/flutter_test.dart'; import 'package:hmg_patient_app_new/widgets/date_range_selector/viewmodel/date_range_calendar_model.dart'; /// Comprehensive test to analyze date conversion issues between Gregorian and Hijri calendars /// This test simulates the onDobChange method logic and tests 200 years of dates void main() { group('Date Conversion Analysis - 200 Years', () { // Test results storage final List results = []; final List errors = []; test('Test Gregorian to Hijri conversion for 200 years', () { print('\n========================================'); print('GREGORIAN TO HIJRI CONVERSION TEST'); print('Testing dates from 1925 to 2125 (200 years)'); print('========================================\n'); int totalDates = 0; int successfulConversions = 0; int failedConversions = 0; // Test dates from 1925 to 2125 (200 years) for (int year = 1925; year <= 2125; year++) { // Test all 12 months for (int month = 1; month <= 12; month++) { // Test key days in each month (1st, 15th, last day) final daysToTest = [1, 15, _getLastDayOfMonth(year, month)]; for (int day in daysToTest) { totalDates++; try { // Create Gregorian date final gregorianDate = DateTime(year, month, day); final isoString = gregorianDate.toIso8601String(); // Test parsing (this is where the error occurs) final parsedDate = DateTime.parse(isoString); // Test Hijri conversion final hijriDate = HijriGregConverter.gregorianToHijri(parsedDate); // Test creating DateTime from Hijri components final hijriDateTime = DateTime(hijriDate.year, hijriDate.month, hijriDate.day); // Test formatting methods final apiFormat = _formatDateForApi(isoString); final displayFormat = _formatDateToDisplay(isoString); final hijriDisplayFormat = _formatHijriDateToDisplay(hijriDateTime.toIso8601String()); // Store successful result results.add(DateConversionResult( gregorianDate: gregorianDate, isoString: isoString, hijriYear: hijriDate.year, hijriMonth: hijriDate.month, hijriDay: hijriDate.day, apiFormat: apiFormat, displayFormat: displayFormat, hijriDisplayFormat: hijriDisplayFormat, success: true, )); successfulConversions++; } catch (e) { failedConversions++; final errorMsg = 'ERROR on $year-${month.toString().padLeft(2, '0')}-${day.toString().padLeft(2, '0')}: $e'; errors.add(errorMsg); print(errorMsg); results.add(DateConversionResult( gregorianDate: DateTime(year, month, day), isoString: 'FAILED', hijriYear: 0, hijriMonth: 0, hijriDay: 0, apiFormat: 'FAILED', displayFormat: 'FAILED', hijriDisplayFormat: 'FAILED', success: false, errorMessage: e.toString(), )); } } } // Print progress every 10 years if (year % 10 == 0) { print('Processed up to year $year... (Success: $successfulConversions, Failed: $failedConversions)'); } } // Print summary print('\n========================================'); print('TEST SUMMARY'); print('========================================'); print('Total dates tested: $totalDates'); print('Successful conversions: $successfulConversions'); print('Failed conversions: $failedConversions'); print('Success rate: ${(successfulConversions / totalDates * 100).toStringAsFixed(2)}%'); print('========================================\n'); // Print all errors if (errors.isNotEmpty) { print('\n========================================'); print('ALL ERRORS (${errors.length} total):'); print('========================================'); for (var error in errors) { print(error); } } // Print sample successful conversions if (results.where((r) => r.success).isNotEmpty) { print('\n========================================'); print('SAMPLE SUCCESSFUL CONVERSIONS (First 5):'); print('========================================'); int count = 0; for (var result in results.where((r) => r.success)) { if (count >= 5) break; print('Gregorian: ${result.gregorianDate}'); print(' ISO: ${result.isoString}'); print(' Hijri: ${result.hijriYear}-${result.hijriMonth}-${result.hijriDay}'); print(' API Format: ${result.apiFormat}'); print(' Display Format: ${result.displayFormat}'); print(' Hijri Display: ${result.hijriDisplayFormat}'); print('---'); count++; } } // Test should fail if there are any errors expect(failedConversions, 0, reason: 'Found $failedConversions failed conversions'); }); test('Test specific edge cases', () { print('\n========================================'); print('EDGE CASES TEST'); print('========================================\n'); final edgeCases = [ DateTime(1900, 1, 1), // Very old date DateTime(1970, 1, 1), // Unix epoch DateTime(2000, 1, 1), // Y2K DateTime(2000, 2, 29), // Leap year DateTime(2001, 2, 28), // Non-leap year DateTime(2024, 12, 31), // Recent date DateTime(2025, 1, 1), // Near future DateTime(2100, 12, 31), // Far future DateTime(2124, 2, 29), // Leap year in far future DateTime(2125, 12, 31), // End of test range ]; for (var testDate in edgeCases) { try { final isoString = testDate.toIso8601String(); final parsedDate = DateTime.parse(isoString); final hijriDate = HijriGregConverter.gregorianToHijri(parsedDate); print('✓ ${testDate.toString().split(' ')[0]} -> Hijri: ${hijriDate.year}-${hijriDate.month}-${hijriDate.day}'); } catch (e) { print('✗ ${testDate.toString().split(' ')[0]} -> ERROR: $e'); fail('Edge case failed: $testDate - $e'); } } }); test('Test DateRangCalenderModel with Umm al-Qura offset', () { print('\n========================================'); print('UMM AL-QURA OFFSET TEST'); print('========================================\n'); // We can't fully test DateRangCalenderModel without full context, // but we can test the conversion logic final testDates = [ DateTime(2024, 1, 1), DateTime(2024, 6, 15), DateTime(2024, 12, 31), DateTime(2025, 1, 1), ]; for (var testDate in testDates) { try { // Simulate the Umm al-Qura offset (-1 day) final adjustedDate = testDate.subtract(const Duration(days: 1)); final hijriDate = HijriGregConverter.gregorianToHijri(adjustedDate); print('Original: ${testDate.toString().split(' ')[0]}'); print(' Adjusted (-1 day): ${adjustedDate.toString().split(' ')[0]}'); print(' Hijri: ${hijriDate.year}-${hijriDate.month}-${hijriDate.day}'); print('---'); } catch (e) { print('ERROR on ${testDate.toString().split(' ')[0]}: $e'); fail('Umm al-Qura offset test failed: $testDate - $e'); } } }); test('Test problematic date formats', () { print('\n========================================'); print('PROBLEMATIC DATE FORMATS TEST'); print('========================================\n'); final problematicFormats = [ '2024-01-01T00:00:00.000', '2024-01-01T00:00:00.000Z', '2024-01-01T00:00:00', '2024-01-01', '2024-1-1', '2024-01-1', '2024-1-01', ]; for (var format in problematicFormats) { try { final parsed = DateTime.parse(format); print('✓ Format "$format" parsed successfully: ${parsed.toString()}'); } catch (e) { print('✗ Format "$format" FAILED to parse: $e'); } } }); }); } // Helper function to get last day of month int _getLastDayOfMonth(int year, int month) { if (month == 12) { return DateTime(year + 1, 1, 1).subtract(const Duration(days: 1)).day; } return DateTime(year, month + 1, 1).subtract(const Duration(days: 1)).day; } // Replicate Utils methods for testing String _formatDateForApi(String isoDateString) { try { final dateTime = DateTime.parse(isoDateString); final year = dateTime.year.toString(); final month = dateTime.month.toString().padLeft(2, '0'); final day = dateTime.day.toString().padLeft(2, '0'); return '$day/$month/$year'; } catch (e) { return 'ERROR: $e'; } } String _formatDateToDisplay(String isoDateString) { try { final dateTime = DateTime.parse(isoDateString); final day = dateTime.day.toString().padLeft(2, '0'); final year = dateTime.year.toString(); const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; final month = monthNames[dateTime.month - 1]; return '$day $month, $year'; } catch (e) { return 'ERROR: $e'; } } String _formatHijriDateToDisplay(String hijriDateString) { try { final datePart = hijriDateString.split("T").first; final parts = datePart.split('-'); if (parts.length != 3) return 'ERROR: Invalid format'; final day = parts[2].padLeft(2, '0'); final year = parts[0]; const hijriMonthNames = [ 'Muharram', 'Safar', 'Rabi I', 'Rabi II', 'Jumada I', 'Jumada II', 'Rajab', 'Sha\'ban', 'Ramadan', 'Shawwal', 'Dhu al-Qi\'dah', 'Dhu al-Hijjah' ]; final monthIndex = int.tryParse(parts[1]) ?? 1; final month = hijriMonthNames[monthIndex - 1]; return '$day $month, $year'; } catch (e) { return 'ERROR: $e'; } } // Stub for HijriGregConverter (since we're testing the logic) class HijriGregConverter { static HijriGregDate gregorianToHijri(DateTime gregorianDate) { // This is a simplified conversion for testing // In reality, this would use the actual Hijri calendar library // Basic astronomical calculation (not exact Umm al-Qura) final julianDay = _gregorianToJulianDay(gregorianDate); final hijriDate = _julianDayToHijri(julianDay); return hijriDate; } static int _gregorianToJulianDay(DateTime date) { int a = (14 - date.month) ~/ 12; int y = date.year + 4800 - a; int m = date.month + 12 * a - 3; return date.day + (153 * m + 2) ~/ 5 + 365 * y + y ~/ 4 - y ~/ 100 + y ~/ 400 - 32045; } static HijriGregDate _julianDayToHijri(int julianDay) { // Basic conversion (simplified for testing) int l = julianDay - 1948440 + 10632; int n = (l - 1) ~/ 10631; l = l - 10631 * n + 354; int j = ((10985 - l) ~/ 5316) * ((50 * l) ~/ 17719) + (l ~/ 5670) * ((43 * l) ~/ 15238); l = l - ((30 - j) ~/ 15) * ((17719 * j) ~/ 50) - (j ~/ 16) * ((15238 * j) ~/ 43) + 29; int month = (24 * l) ~/ 709; int day = l - (709 * month) ~/ 24; int year = 30 * n + j - 30; return HijriGregDate(year: year, month: month, day: day); } } class HijriGregDate { final int year; final int month; final int day; HijriGregDate({required this.year, required this.month, required this.day}); } // Data class to store test results class DateConversionResult { final DateTime gregorianDate; final String isoString; final int hijriYear; final int hijriMonth; final int hijriDay; final String apiFormat; final String displayFormat; final String hijriDisplayFormat; final bool success; final String? errorMessage; DateConversionResult({ required this.gregorianDate, required this.isoString, required this.hijriYear, required this.hijriMonth, required this.hijriDay, required this.apiFormat, required this.displayFormat, required this.hijriDisplayFormat, required this.success, this.errorMessage, }); }