Skip to content

Fixes #2471. Fix timer constructor tests. Add check for microtasks #2472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions LibTest/async/Timer/Timer.periodic_A01_t02.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// @assertion
/// factory Timer.periodic(Duration duration, void callback(Timer timer))
///
/// Creates a new repeating timer.
///
/// The callback is invoked repeatedly with duration intervals until canceled
/// with the cancel function.
///
/// The exact timing depends on the underlying timer implementation. No more
/// than n callbacks will be made in duration * n time, but the time between two
/// consecutive callbacks can be shorter and longer than duration.
///
/// In particular, an implementation may schedule the next callback, e.g., a
/// duration after either when the previous callback ended, when the previous
/// callback started, or when the previous callback was scheduled for - even if
/// the actual callback was delayed.
///
/// @description Checks that no more than `n` callbacks are made in
/// `duration * n` time
/// @author [email protected]

import "dart:async";
import "../../../Utils/expect.dart";

void check(int durationMs, int n) {
int callbacksCount = 0;
Duration duration = Duration(milliseconds: durationMs);
Stopwatch sw = Stopwatch();

sw.start();
Timer.periodic(duration, (Timer timer) {
callbacksCount++;
if (sw.elapsedMilliseconds <= n * durationMs) {
Expect.isTrue(
callbacksCount <= n,
"Expected no more than $n callbacks for ${n * durationMs}ms, but " +
"actually there were $callbacksCount for " +
"${sw.elapsedMilliseconds}ms");
} else {
timer.cancel();
asyncEnd();
}
});
}

void main() {
asyncStart(4);
check(1, 5);
check(10, 5);
check(50, 5);
check(100, 5);
}
54 changes: 27 additions & 27 deletions LibTest/async/Timer/Timer.periodic_A02_t01.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,46 @@

/// @assertion
/// factory Timer.periodic(Duration duration, void callback(Timer timer))
/// ...
/// A negative duration is treated the same as [Duration.zero]
///
/// A negative duration is treated the same as a duration of 0
///
/// @description Checks that negative duration is accepted and treated like a 0.
/// @description Checks that negative duration is accepted and treated as
/// [Duration.zero].
/// @author kaigorodov

import "dart:async";
import "../../../Utils/expect.dart";

// Most browsers can trigger timers too early. Test data shows instances where
// timers fire even 15ms early. We add a safety margin to prevent flakiness
// when running this test on affected platforms.
Duration safetyMargin = const bool.fromEnvironment('dart.library.js')
? Duration(milliseconds: 40)
: Duration.zero;
check(int durationInMs) {
bool earlierZeroTimerTriggered = false;
bool laterZeroTimerTriggered = false;

// Timer is not started immediately but waits for microtask queue. So the
// timer can be started with some unpredictable delay. Therefore let's check
// that it triggers not earlier that previously-scheduled zero-duration timer
// and not earlier that later-scheduled zero-duration timer
Timer.periodic(Duration.zero, (timer) {
earlierZeroTimerTriggered = true;
timer.cancel();
});

check(int delay) {
final maxCount = 5;
int count = 0;
Stopwatch sw = new Stopwatch();
sw.start();
Timer.periodic(Duration(milliseconds: durationInMs), (Timer timer) {
Expect.isTrue(earlierZeroTimerTriggered);
Expect.isFalse(laterZeroTimerTriggered);
timer.cancel();
});

asyncStart();
new Timer.periodic(durationInMilliseconds(delay), (Timer timer) {
count++;
Duration expected = durationInMilliseconds(40); // Expect actual time near 0
Duration actual = sw.elapsed;
Expect.isTrue(actual <= expected + safetyMargin,
"expected=${expected + safetyMargin}, actual=$actual");
if (count == maxCount) {
timer.cancel();
asyncEnd();
}
Timer.periodic(Duration.zero, (timer) {
laterZeroTimerTriggered = true;
timer.cancel();
asyncEnd();
});
}

main() {
asyncStart();
asyncStart(4);
check(0);
check(-10);
check(-100);
check(-1000);
asyncEnd();
}
53 changes: 53 additions & 0 deletions LibTest/async/Timer/Timer.periodic_A02_t02.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// @assertion
/// factory Timer.periodic(Duration duration, void callback(Timer timer))
/// ...
/// A negative duration is treated the same as [Duration.zero]
///
/// @description Checks that negative duration is accepted and treated as
/// [Duration.zero]. Test that timer waits for microtasks queue before
/// triggering
/// @author [email protected]

import "dart:async";
import "../../../Utils/expect.dart";

const maxMicrotasks = 10;
int microtasksCount = 0;

void microtask() {
if (++microtasksCount < maxMicrotasks) {
scheduleMicrotask(microtask);
}
}

Future<void> check(int durationInMs, int n) {
Completer<void> completer = Completer();
int timerCount = 0;

scheduleMicrotask(microtask);

Timer.periodic(Duration(milliseconds: durationInMs), (Timer timer) {
Expect.equals(maxMicrotasks, microtasksCount);
microtasksCount = 0;
if (++timerCount == n) {
timer.cancel();
completer.complete();
asyncEnd();
} else {
scheduleMicrotask(microtask);
}
});
return completer.future;
}

main() async {
asyncStart(4);
await check(0, 5);
await check(-10, 5);
await check(-100, 5);
await check(-1000, 3);
}
8 changes: 1 addition & 7 deletions LibTest/async/Timer/Timer_A01_t01.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ check(int delayms) {
Duration delay = durationInMilliseconds(delayms);
Stopwatch sw = new Stopwatch();
sw.start();

asyncStart();
new Timer(delay, () {
Duration actual = sw.elapsed;
Expect.isTrue(delay <= actual + safetyMargin,
Expand All @@ -35,16 +33,12 @@ check(int delayms) {
}

main() {
asyncStart();
asyncStart(7);
check(150);
check(100);
check(50);
check(25);
check(10);
check(2);
check(1);
check(0);
check(-5);
check(-50);
asyncEnd();
}
43 changes: 22 additions & 21 deletions LibTest/async/Timer/Timer_A02_t01.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,42 @@

/// @assertion factory Timer(Duration duration, void callback())
///
/// A negative duration is treated the same as a duration of 0.
/// A negative duration is treated the same as [Duration.zero]
///
/// @description Checks that negative duration is accepted.
/// @description Checks that negative duration is accepted and treated as
/// [Duration.zero].
/// @author kaigorodov

import "dart:async";
import "../../../Utils/expect.dart";

// Most browsers can trigger timers too early. Test data shows instances where
// timers fire even 15ms early. We add a safety margin to prevent flakiness
// when running this test on affected platforms.
Duration safetyMargin = const bool.fromEnvironment('dart.library.js')
? Duration(milliseconds: 40)
: Duration.zero;
check(int durationInMs) {
bool earlierZeroTimerTriggered = false;
bool laterZeroTimerTriggered = false;

check(int delayms) {
Stopwatch sw = new Stopwatch();
sw.start();
// Timer is not started immediately but waits for microtask queue. So the
// timer can be started with some unpredictable delay. Therefore let's check
// that it triggers not earlier that previously-scheduled zero-duration timer
// and not earlier that later-scheduled zero-duration timer
Timer(Duration.zero, () {
earlierZeroTimerTriggered = true;
});

Timer(Duration(milliseconds: durationInMs), () {
Expect.isTrue(earlierZeroTimerTriggered);
Expect.isFalse(laterZeroTimerTriggered);
});

asyncStart();
new Timer(durationInMilliseconds(delayms), () {
Duration expected = durationInMilliseconds(40); // Expect actual time near 0
Duration actual = sw.elapsed;
Expect.isTrue(actual <= expected + safetyMargin,
"expected=${expected + safetyMargin}, actual=$actual");
Timer(Duration.zero, () {
laterZeroTimerTriggered = true;
asyncEnd();
});
}

main() {
asyncStart();
asyncStart(4);
check(0);
check(-1);
check(-10);
check(-100);
check(-1000);
asyncEnd();
check(-500);
}
45 changes: 45 additions & 0 deletions LibTest/async/Timer/Timer_A02_t02.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// @assertion factory Timer(Duration duration, void callback())
///
/// A negative duration is treated the same as [Duration.zero]
///
/// @description Checks that negative duration is accepted and treated as
/// [Duration.zero]. Test that timer waits for microtask queue before the start
/// @author [email protected]

import "dart:async";
import "../../../Utils/expect.dart";

const maxMicrotasks = 10;
int microtasksCount = 0;

void microtask() {
if (++microtasksCount < maxMicrotasks) {
scheduleMicrotask(microtask);
}
}

Future<void> check(int durationInMs, int n) {
Completer<void> completer = Completer();

scheduleMicrotask(microtask);

Timer(Duration(milliseconds: durationInMs), () {
Expect.equals(maxMicrotasks, microtasksCount);
microtasksCount = 0;
completer.complete();
asyncEnd();
});
return completer.future;
}

main() async {
asyncStart(4);
await check(0, 5);
await check(-10, 5);
await check(-100, 5);
await check(-500, 3);
}