Files
TPSchedule/mobile/test/services/notification_service_test.dart
T

154 lines
4.9 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:timezone/data/latest.dart' as tzdata;
import 'package:hepan_everyday/services/local_notification_service.dart';
import 'package:hepan_everyday/services/notification_service.dart';
import 'package:hepan_everyday/domain/schedule_engine.dart';
import 'package:hepan_everyday/domain/app_settings.dart';
import '../domain/schedule_engine_test.dart' show course;
class AlarmGateway extends ReminderGateway {
ReminderPermissions permission = const ReminderPermissions(true, true);
final alarms = <int, ReminderRequest>{};
int permissionRequests = 0;
@override
Future<ReminderPermissions> permissions({required bool request}) async {
if (request) permissionRequests++;
return permission;
}
@override
Future<Set<int>> pendingIds() async => alarms.keys.toSet();
@override
Future<void> schedule(ReminderRequest value) async {
alarms[value.id] = value;
}
@override
Future<void> cancel(int id) async {
alarms.remove(id);
}
}
void main() {
setUpAll(tzdata.initializeTimeZones);
final term = Semester(startDate: DateTime(2026, 9, 9), totalWeeks: 5);
final settings = AppSettings(semester: term);
late AlarmGateway gateway;
late LocalNotificationService service;
setUp(() {
gateway = AlarmGateway();
service = LocalNotificationService(gateway);
});
test(
'continuous course schedules one alarm fifteen minutes before school start',
() async {
final events = ScheduleEngine.occurrences([course(last: 2)], term);
final result = await service.reconcile(
events,
settings,
DateTime.utc(2026, 9, 9),
);
expect(result.scheduledCount, 1);
expect(gateway.alarms, hasLength(1));
expect(
gateway.alarms.values.single.fireAt.toUtc(),
DateTime.utc(2026, 9, 9, 0, 15),
);
expect(gateway.alarms.values.single.id, 1794407394);
expect(gateway.permissionRequests, 0);
},
);
test(
'repeat updates replace one alarm and use changed advance time',
() async {
final events = ScheduleEngine.occurrences([course()], term);
await service.reconcile(events, settings, DateTime.utc(2026, 9, 9));
await service.reconcile(
events,
settings.copyWith(reminderMinutes: 5),
DateTime.utc(2026, 9, 9),
);
expect(gateway.alarms, hasLength(1));
expect(
gateway.alarms.values.single.fireAt.toUtc(),
DateTime.utc(2026, 9, 9, 0, 25),
);
},
);
test(
'past reminder, demo and disabled settings remove pending own alarms',
() async {
final events = ScheduleEngine.occurrences([course()], term);
await service.reconcile(events, settings, DateTime.utc(2026, 9, 9));
expect(gateway.alarms, hasLength(1));
await service.reconcile(
events,
settings,
DateTime.utc(2026, 9, 9, 0, 20),
);
expect(gateway.alarms, isEmpty);
await service.reconcile(events, settings, DateTime.utc(2026, 9, 9));
expect(gateway.alarms, hasLength(1));
await service.reconcile(
events,
settings.copyWith(remindersEnabled: false),
DateTime.utc(2026, 9, 9),
);
expect(gateway.alarms, isEmpty);
},
);
test('denied notifications and denied exact alarm have distinct effective status', () async {
final events = ScheduleEngine.occurrences([course()], term);
gateway.permission = const ReminderPermissions(false, false);
expect(
(await service.reconcile(
events,
settings,
DateTime.utc(2026, 9, 9),
)).status,
ReminderStatus.permissionDenied,
);
expect(gateway.alarms, isEmpty);
gateway.permission = const ReminderPermissions(true, false);
expect(
(await service.reconcile(
events,
settings,
DateTime.utc(2026, 9, 9),
)).status,
ReminderStatus.inexact,
);
expect(gateway.alarms.values.single.exact, isFalse);
});
test('permission revoked after scheduling cancels previous alarms', () async {
final events = ScheduleEngine.occurrences([course()], term);
await service.reconcile(events, settings, DateTime.utc(2026, 9, 9));
gateway.permission = const ReminderPermissions(false, false);
final result = await service.reconcile(
events,
settings,
DateTime.utc(2026, 9, 9),
);
expect(result.status, ReminderStatus.permissionDenied);
expect(gateway.alarms, isEmpty);
});
test(
'large semester keeps at most four hundred earliest reminders',
() async {
final many = ScheduleEngine.occurrences(
List.generate(501, (i) => course(id: 'class-$i')),
term,
);
final result = await service.reconcile(
many,
settings,
DateTime.utc(2026, 9, 9),
);
expect(result.scheduledCount, 400);
expect(gateway.alarms, hasLength(400));
expect(result.message, contains('后续'));
},
);
}