Fix cached reminder recovery and retain pre-reconcile idle diagnostics
This commit is contained in:
@@ -7,6 +7,39 @@ import 'package:hepan_everyday/services/local_notification_service.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
test(
|
||||
'system handle audit only accepts IDs from the requested cache',
|
||||
() async {
|
||||
const system = MethodChannel('com.tpschedule.app/reminders');
|
||||
final messenger =
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger;
|
||||
messenger.setMockMethodCallHandler(system, (call) async {
|
||||
expect(call.method, 'findMissingAlarmHandles');
|
||||
expect((call.arguments as List).toSet(), {11, 22});
|
||||
return [22, 999];
|
||||
});
|
||||
addTearDown(() => messenger.setMockMethodCallHandler(system, null));
|
||||
expect(await PluginReminderGateway().missingSystemIds({11, 22}), {22});
|
||||
},
|
||||
);
|
||||
test(
|
||||
'optional handle audit failure does not prevent reconciliation',
|
||||
() async {
|
||||
const system = MethodChannel('com.tpschedule.app/reminders');
|
||||
final messenger =
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger;
|
||||
var calls = 0;
|
||||
messenger.setMockMethodCallHandler(system, (_) async {
|
||||
calls++;
|
||||
throw PlatformException(code: 'reminder_system_unavailable');
|
||||
});
|
||||
addTearDown(() => messenger.setMockMethodCallHandler(system, null));
|
||||
final gateway = PluginReminderGateway();
|
||||
expect(await gateway.missingSystemIds({11}), isEmpty);
|
||||
expect(await gateway.missingSystemIds({}), isEmpty);
|
||||
expect(calls, 1);
|
||||
},
|
||||
);
|
||||
test('fresh notification initialization creates the course category before checks', () async {
|
||||
debugDefaultTargetPlatformOverride = TargetPlatform.android;
|
||||
AndroidFlutterLocalNotificationsPlugin.registerWith();
|
||||
|
||||
@@ -13,6 +13,15 @@ class AlarmGateway extends ReminderGateway {
|
||||
final alarms = <int, ReminderRequest>{};
|
||||
int permissionRequests = 0;
|
||||
bool dropWrites = false;
|
||||
final missingHandles = <int>{};
|
||||
Set<int> lastAuditedIds = {};
|
||||
int scheduleCalls = 0;
|
||||
@override
|
||||
Future<Set<int>> missingSystemIds(Set<int> ids) async {
|
||||
lastAuditedIds = {...ids};
|
||||
return missingHandles.intersection(ids);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ReminderPermissions> permissions({required bool request}) async {
|
||||
if (request) permissionRequests++;
|
||||
@@ -23,7 +32,9 @@ class AlarmGateway extends ReminderGateway {
|
||||
Future<Set<int>> pendingIds() async => alarms.keys.toSet();
|
||||
@override
|
||||
Future<void> schedule(ReminderRequest value) async {
|
||||
scheduleCalls++;
|
||||
if (!dropWrites) alarms[value.id] = value;
|
||||
missingHandles.remove(value.id);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -48,6 +59,32 @@ void main() {
|
||||
return AppSnapshot.fromJson(json).settings;
|
||||
}
|
||||
|
||||
test(
|
||||
'overdue cached reminders are audited before removal on warm resume',
|
||||
() async {
|
||||
final events = ScheduleEngine.occurrences([course()], term);
|
||||
await service.reconcile(events, settings, DateTime.utc(2026, 9, 9));
|
||||
final cached = gateway.alarms.keys.toSet();
|
||||
expect(cached, isNotEmpty);
|
||||
await service.reconcile(events, settings, DateTime.utc(2027, 1, 1));
|
||||
expect(gateway.lastAuditedIds, cached);
|
||||
expect(gateway.alarms, isEmpty);
|
||||
},
|
||||
);
|
||||
|
||||
test('cached fingerprint does not hide a missing system trigger', () async {
|
||||
final events = ScheduleEngine.occurrences([course()], term);
|
||||
final now = DateTime.utc(2026, 9, 9);
|
||||
await service.reconcile(events, settings, now);
|
||||
final previous = gateway.scheduleCalls;
|
||||
gateway.missingHandles.addAll(gateway.alarms.keys);
|
||||
await service.reconcile(events, settings, now);
|
||||
expect(gateway.scheduleCalls, previous + 1);
|
||||
expect(gateway.missingHandles, isEmpty);
|
||||
await service.reconcile(events, settings, now);
|
||||
expect(gateway.scheduleCalls, previous + 1);
|
||||
});
|
||||
|
||||
test(
|
||||
'does not report success when native scheduling did not persist',
|
||||
() async {
|
||||
|
||||
Reference in New Issue
Block a user