import 'package:test/test.dart'; import 'package:quiver/testing/async.dart'; import 'package:quiver/time.dart'; import 'package:flutter_web_ui/src/engine.dart'; void main() { group(AlarmClock, () { _alarmClockTests(); }); } void _alarmClockTests() { int callCount = 0; void testCallback() { callCount += 1; } setUp(() { callCount = 0; }); testAsync('AlarmClock calls the callback in the future', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; // There should be no timers scheduled until we set a non-null datetime. expect(fakeAsync.nonPeriodicTimerCount, 0); alarm.datetime = clock.fromNow(minutes: 1); // There should be exactly 1 timer scheduled. expect(fakeAsync.nonPeriodicTimerCount, 1); // No time has passed; the callback should not be called. expect(callCount, 0); // Not enough time has passed; the callback should not be called. fakeAsync.elapse(const Duration(seconds: 30)); expect(callCount, 0); // Exactly 1 minute has passed; fire the callback. fakeAsync.elapse(const Duration(seconds: 30)); expect(callCount, 1); // Timers should be cleaned up. expect(fakeAsync.nonPeriodicTimerCount, 0); // Rescheduling. alarm.datetime = clock.fromNow(minutes: 1); expect(fakeAsync.nonPeriodicTimerCount, 1); fakeAsync.elapse(const Duration(minutes: 1)); expect(fakeAsync.nonPeriodicTimerCount, 0); expect(callCount, 2); }); testAsync('AlarmClock does nothing when new datetime is the same', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; alarm.datetime = clock.fromNow(minutes: 1); expect(fakeAsync.nonPeriodicTimerCount, 1); expect(callCount, 0); alarm.datetime = alarm.datetime.add(Duration.zero); expect(fakeAsync.nonPeriodicTimerCount, 1); expect(callCount, 0); fakeAsync.elapse(const Duration(seconds: 30)); alarm.datetime = alarm.datetime.add(Duration.zero); expect(fakeAsync.nonPeriodicTimerCount, 1); expect(callCount, 0); fakeAsync.elapse(const Duration(seconds: 30)); expect(fakeAsync.nonPeriodicTimerCount, 0); expect(callCount, 1); }); testAsync('AlarmClock does not call the callback in the past', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; alarm.datetime = clock.ago(minutes: 1); // No timers scheduled for past dates. expect(fakeAsync.nonPeriodicTimerCount, 0); expect(callCount, 0); }); testAsync('AlarmClock reschedules to a future time', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; alarm.datetime = clock.fromNow(minutes: 1); expect(fakeAsync.nonPeriodicTimerCount, 1); expect(callCount, 0); fakeAsync.elapse(const Duration(seconds: 30)); expect(callCount, 0); // Reschedule. alarm.datetime = alarm.datetime.add(const Duration(minutes: 1)); fakeAsync.elapse(const Duration(minutes: 1)); // Still no calls because we rescheduled. expect(callCount, 0); fakeAsync.elapse(const Duration(seconds: 30)); expect(callCount, 1); expect(fakeAsync.nonPeriodicTimerCount, 0); }); testAsync('AlarmClock reschedules to an earlier time', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; alarm.datetime = clock.fromNow(minutes: 1); expect(fakeAsync.nonPeriodicTimerCount, 1); expect(callCount, 0); fakeAsync.elapse(const Duration(seconds: 30)); expect(callCount, 0); // Reschedule to an earlier time that's still in the future. alarm.datetime = alarm.datetime.subtract(const Duration(seconds: 15)); fakeAsync.elapse(const Duration(seconds: 45)); expect(callCount, 1); expect(fakeAsync.nonPeriodicTimerCount, 0); }); testAsync('AlarmClock cancels the timer when datetime is null', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; alarm.datetime = clock.fromNow(minutes: 1); expect(fakeAsync.nonPeriodicTimerCount, 1); // Cancel. alarm.datetime = null; expect(fakeAsync.nonPeriodicTimerCount, 0); expect(callCount, 0); // Make sure nothing fires even if we wait long enough. fakeAsync.elapse(const Duration(minutes: 2)); expect(callCount, 0); expect(fakeAsync.nonPeriodicTimerCount, 0); }); testAsync('AlarmClock cancels the timer when datetime is in the past', (FakeAsync fakeAsync) { final Clock clock = fakeAsync.getClock(DateTime(2019, 1, 24)); final AlarmClock alarm = AlarmClock(clock.now); alarm.callback = testCallback; alarm.datetime = clock.fromNow(minutes: 1); expect(fakeAsync.nonPeriodicTimerCount, 1); fakeAsync.elapse(const Duration(seconds: 30)); expect(callCount, 0); expect(fakeAsync.nonPeriodicTimerCount, 1); // Cancel. alarm.datetime = clock.ago(seconds: 1); expect(fakeAsync.nonPeriodicTimerCount, 0); expect(callCount, 0); // Make sure nothing fires even if we wait long enough. fakeAsync.elapse(const Duration(minutes: 2)); expect(callCount, 0); expect(fakeAsync.nonPeriodicTimerCount, 0); }); } typedef FakeAsyncTest = void Function(FakeAsync); void testAsync(String description, FakeAsyncTest fn) { test(description, () { FakeAsync().run(fn); }); }