import 'package:flutter_test/flutter_test.dart'; import 'package:jamshalat_masjid_screen/core/enums.dart'; import 'package:jamshalat_masjid_screen/data/local/models.dart'; import 'package:jamshalat_masjid_screen/data/services/hijri_service.dart'; import 'package:jamshalat_masjid_screen/data/services/sync_service.dart'; import 'package:jamshalat_masjid_screen/data/services/update_service.dart'; void main() { group('PrayerName display labels', () { test('uses Jumat label for Friday dzuhur', () { expect( PrayerName.dzuhur.displayLabel(isFriday: true), 'JUMAT', ); expect( PrayerName.dzuhur.displayLabel(isFriday: false), 'Dzuhur', ); }); test('marks fardhu prayers correctly', () { expect(PrayerName.subuh.isFardhu, isTrue); expect(PrayerName.imsak.isFardhu, isFalse); }); }); group('AppSettings copyWith', () { test('preserves defaults and overrides selected fields', () { final settings = AppSettings(); final updated = settings.copyWith( masjidName: 'Masjid Raya', cityIdApi: '1301', iqomahDzuhur: 12, lastAutoSyncAttemptDate: '2026-03-31T09:00:00.000', ); expect(updated.masjidName, 'Masjid Raya'); expect(updated.cityIdApi, '1301'); expect(updated.iqomahDzuhur, 12); expect(updated.lastAutoSyncAttemptDate, '2026-03-31T09:00:00.000'); expect(updated.masjidAddress, settings.masjidAddress); expect(updated.runningTexts, settings.runningTexts); }); }); group('HijriCalendarService parsing', () { test('extracts hijri label from MyQuran calendar response', () { final label = HijriCalendarService.parseHijriLabel({ 'status': true, 'data': { 'hijr': { 'today': 'Senin, 11 Syawal 1447 H', 'day': 11, 'monthName': 'Syawal', 'year': 1447, }, }, }); expect(label, '11 Syawal 1447 H'); }); }); group('ScheduleCacheStatus', () { test('derives cached date range and days left from stored schedules', () { final status = ScheduleCacheStatus.fromSchedules( [ DailyPrayerSchedule( date: '2026-03-01', imsak: '04:20', subuh: '04:30', terbit: '05:45', dhuha: '06:10', dzuhur: '11:55', ashar: '15:10', maghrib: '17:58', isya: '19:05', ), DailyPrayerSchedule( date: '2026-04-30', imsak: '04:19', subuh: '04:29', terbit: '05:44', dhuha: '06:09', dzuhur: '11:54', ashar: '15:09', maghrib: '17:57', isya: '19:04', ), ], DateTime(2026, 3, 30), ); expect(status.hasData, isTrue); expect(status.startDate, DateTime(2026, 3, 1)); expect(status.endDate, DateTime(2026, 4, 30)); expect(status.cachedDays, 2); expect(status.daysUntilRefresh, 31); }); test('rolling window stale key helper keeps only current and next month', () { final staleKeys = SyncService.staleScheduleKeys( [ '2026-02-28', '2026-03-01', '2026-04-30', '2026-05-01', 'invalid-key', ], DateTime(2026, 3, 30), ); expect( staleKeys, containsAll(['2026-02-28', '2026-05-01', 'invalid-key']), ); expect(staleKeys, isNot(contains('2026-03-01'))); expect(staleKeys, isNot(contains('2026-04-30'))); }); test('normalizes mixed date formats and de-duplicates same day rows', () { final status = ScheduleCacheStatus.fromSchedules( [ DailyPrayerSchedule( date: '2026-4-6', imsak: '04:20', subuh: '04:30', terbit: '05:45', dhuha: '06:10', dzuhur: '11:55', ashar: '15:10', maghrib: '17:58', isya: '19:05', ), DailyPrayerSchedule( date: '2026-04-06', imsak: '04:20', subuh: '04:30', terbit: '05:45', dhuha: '06:10', dzuhur: '11:55', ashar: '15:10', maghrib: '17:58', isya: '19:05', ), DailyPrayerSchedule( date: '2026-04-07', imsak: '04:21', subuh: '04:31', terbit: '05:46', dhuha: '06:11', dzuhur: '11:56', ashar: '15:11', maghrib: '17:59', isya: '19:06', ), ], DateTime(2026, 4, 6), ); expect(status.startDate, DateTime(2026, 4, 6)); expect(status.endDate, DateTime(2026, 4, 7)); expect(status.cachedDays, 2); expect(status.daysUntilRefresh, 1); }); test('stale key helper accepts non-padded legacy keys', () { final staleKeys = SyncService.staleScheduleKeys( [ '2026-4-6', '2026-5-1', '2026-6-1', ], DateTime(2026, 4, 6), ); expect(staleKeys, contains('2026-6-1')); expect(staleKeys, isNot(contains('2026-4-6'))); expect(staleKeys, isNot(contains('2026-5-1'))); }); }); group('AppUpdateInfo parsing', () { test('supports +0700 timezone format and preserves multiline notes', () { final info = AppUpdateInfo.fromJson({ 'latest_version': '1.0.0', 'version_code': 1, 'apk_url': 'https://files.jamshalat.com/app.apk', 'published_at': '2026-04-01T12:05:23+0700', 'notes': 'Initial APK\n\n- Menu Admin Baru: Tentang\n- Akses Admin Panel', 'sha256': 'abc123', 'min_supported_version_code': 1, }); expect(info.isValid, isTrue); expect(info.publishedAt, isNotNull); expect(info.publishedAt!.toUtc(), DateTime.utc(2026, 4, 1, 5, 5, 23)); expect(info.notes, contains('\n\n- Menu Admin Baru: Tentang')); expect(info.notes, contains('\n- Akses Admin Panel')); }); }); }