You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_Patient_App_New/test/date_conversion_test.dart

366 lines
12 KiB
Dart

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<DateConversionResult> results = [];
final List<String> 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,
});
}