If an IdleManager or TimeoutManager had been scheduled, it would not get destroyed until it was executed by the main loop, causing criticals if the objects enclosed by its callback had been destroyed. This adds a weak reference to the manager object itself when scheduling on the main loop, so it can get safely dropped.
128 lines
3.8 KiB
Vala
128 lines
3.8 KiB
Vala
/*
|
|
* Copyright 2016 Michael Gratton <mike@vee.net>
|
|
*
|
|
* This software is licensed under the GNU Lesser General Public License
|
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
|
*/
|
|
|
|
class Geary.TimeoutManagerTest : TestCase {
|
|
|
|
// add_seconds seems to vary wildly, so needs a large epsilon
|
|
private const double SECONDS_EPSILON = 1.8;
|
|
|
|
private const double MILLISECONDS_EPSILON = 0.1;
|
|
|
|
|
|
private class WeakRefTest : GLib.Object {
|
|
|
|
public TimeoutManager test { get; private set; }
|
|
|
|
public WeakRefTest() { // Pass in an arg to ensure the closure is non-trivial
|
|
string arg = "my hovercraft is full of eels";
|
|
this.test = new TimeoutManager.milliseconds(
|
|
10, () => {
|
|
do_stuff(arg);
|
|
}
|
|
);
|
|
|
|
// Pass
|
|
this.test.start();
|
|
}
|
|
|
|
private void do_stuff(string arg) {
|
|
// This should never get called
|
|
assert(false);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public TimeoutManagerTest() {
|
|
base("Geary.TimeoutManagerTest");
|
|
add_test("weak_ref", callback_weak_ref);
|
|
add_test("start_reset", start_reset);
|
|
if (Test.slow()) {
|
|
add_test("seconds", seconds);
|
|
add_test("milliseconds", milliseconds);
|
|
add_test("repeat_forever", repeat_forever);
|
|
}
|
|
}
|
|
|
|
public void callback_weak_ref() throws GLib.Error {
|
|
WeakRefTest? owner = new WeakRefTest();
|
|
double duration = owner.test.interval;
|
|
GLib.WeakRef weak_ref = GLib.WeakRef(owner.test);
|
|
|
|
// Should make both objects null even though the even loop
|
|
// hasn't run and hence the callback hasn't been called.
|
|
owner = null;
|
|
assert_null(weak_ref.get());
|
|
|
|
// Pump the loop until the timeout has passed so that the
|
|
// callback can get called.
|
|
Timer timer = new Timer();
|
|
timer.start();
|
|
while (timer.elapsed() < (duration / 1000) * 2) {
|
|
this.main_loop.iteration(false);
|
|
}
|
|
}
|
|
|
|
public void start_reset() throws Error {
|
|
TimeoutManager test = new TimeoutManager.seconds(1, () => { /* noop */ });
|
|
assert(!test.is_running);
|
|
test.start();
|
|
assert(test.is_running);
|
|
test.reset();
|
|
assert(!test.is_running);
|
|
}
|
|
|
|
public void seconds() throws Error {
|
|
Timer timer = new Timer();
|
|
|
|
TimeoutManager test = new TimeoutManager.seconds(1, () => { timer.stop(); });
|
|
test.start();
|
|
|
|
timer.start();
|
|
while (test.is_running && timer.elapsed() < SECONDS_EPSILON) {
|
|
this.main_loop.iteration(true);
|
|
}
|
|
|
|
assert_epsilon(timer.elapsed(), 1.0, SECONDS_EPSILON);
|
|
}
|
|
|
|
public void milliseconds() throws Error {
|
|
Timer timer = new Timer();
|
|
|
|
TimeoutManager test = new TimeoutManager.milliseconds(100, () => { timer.stop(); });
|
|
test.start();
|
|
|
|
timer.start();
|
|
while (test.is_running && timer.elapsed() < 100 + MILLISECONDS_EPSILON) {
|
|
this.main_loop.iteration(true);
|
|
}
|
|
|
|
assert_epsilon(timer.elapsed(), 0.1, MILLISECONDS_EPSILON);
|
|
}
|
|
|
|
public void repeat_forever() throws Error {
|
|
Timer timer = new Timer();
|
|
int count = 0;
|
|
|
|
TimeoutManager test = new TimeoutManager.seconds(1, () => { count++; });
|
|
test.repetition = TimeoutManager.Repeat.FOREVER;
|
|
test.start();
|
|
|
|
timer.start();
|
|
while (count < 2 && timer.elapsed() < SECONDS_EPSILON * 2) {
|
|
this.main_loop.iteration(true);
|
|
}
|
|
timer.stop();
|
|
|
|
assert_epsilon(timer.elapsed(), 2.0, SECONDS_EPSILON * 2);
|
|
}
|
|
|
|
private inline void assert_epsilon(double actual, double expected, double epsilon) {
|
|
assert(actual + epsilon >= expected && actual - epsilon <= expected);
|
|
}
|
|
|
|
}
|