From 749096cd38700e240d7cbc90848bb86e59e94626 Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Fri, 10 Apr 2020 12:32:26 +1000 Subject: [PATCH] test/mock-object.vala: Add explicit support for mocking async calls Provide async equivalents of the `blah_call` methods, implement the given async behaviour of expected async calls. --- test/mock-object.vala | 145 +++++++++++++++++++++++++++++++++--------- 1 file changed, 116 insertions(+), 29 deletions(-) diff --git a/test/mock-object.vala b/test/mock-object.vala index c93d82a6..926441cb 100644 --- a/test/mock-object.vala +++ b/test/mock-object.vala @@ -221,7 +221,7 @@ public class ExpectedCall : GLib.Object { * assert_expectations} to ensure that the actual calls made matched * those expected. */ -public interface MockObject { +public interface MockObject : GLib.Object { public static Object box_arg(T value) { @@ -256,39 +256,70 @@ public interface MockObject { } protected bool boolean_call(string name, Object[] args, bool default_return) - throws Error { + throws GLib.Error { ExpectedCall? expected = call_made(name, args); + return check_boolean_call(expected, default_return); + } - bool return_value = default_return; - if (expected.return_value != null) { - return_value = expected.return_value.get_boolean(); + protected async bool boolean_call_async(string name, + Object[] args, + bool default_return) + throws GLib.Error { + ExpectedCall? expected = call_made(name, args); + if (async_call_yield(expected, this.boolean_call_async.callback)) { + yield; } - return return_value; + return check_boolean_call(expected, default_return); } protected R object_call(string name, Object[] args, R default_return) - throws Error { - ExpectedCall? expected = call_made(name, args); - - R? return_object = default_return; - if (expected.return_object != null) { - return_object = (R) expected.return_object; - } - return return_object; - } - - protected R object_or_throw_call(string name, Object[] args, GLib.Error default_error) throws GLib.Error { ExpectedCall? expected = call_made(name, args); - - if (expected.return_object == null) { - throw default_error; - } - return expected.return_object; + return check_object_call(expected, default_return); } - protected void void_call(string name, Object[] args) throws Error { - call_made(name, args); + protected async R object_call_async(string name, + Object[] args, + R default_return) + throws GLib.Error { + ExpectedCall? expected = call_made(name, args); + if (async_call_yield(expected, this.object_call_async.callback)) { + yield; + } + return check_object_call(expected, default_return); + } + + protected R object_or_throw_call(string name, + Object[] args, + GLib.Error default_error) + throws GLib.Error { + ExpectedCall? expected = call_made(name, args); + return check_object_or_throw_call(expected, default_error); + } + + protected async R object_or_throw_call_async(string name, + Object[] args, + GLib.Error default_error) + throws GLib.Error { + ExpectedCall? expected = call_made(name, args); + if (async_call_yield(expected, this.object_or_throw_call_async.callback)) { + yield; + } + return check_object_or_throw_call(expected, default_error); + } + + protected void void_call(string name, Object[] args) throws GLib.Error { + ExpectedCall? expected = call_made(name, args); + check_for_exception(expected); + } + + protected async void void_call_async(string name, Object[] args) + throws GLib.Error { + ExpectedCall? expected = call_made(name, args); + if (async_call_yield(expected, this.void_call_async.callback)) { + yield; + } + check_for_exception(expected); } private ExpectedCall? call_made(string name, Object[] args) throws Error { @@ -301,11 +332,6 @@ public interface MockObject { } expected.called(args); - - if (expected.throw_error != null) { - throw expected.throw_error; - } - return expected; } @@ -352,4 +378,65 @@ public interface MockObject { ); } + private bool async_call_yield(ExpectedCall expected, + GLib.SourceFunc @callback) { + var @yield = false; + if (expected.async_behaviour != CONTINUE) { + expected.async_callback = @callback; + if (expected.async_behaviour == CONTINUE_AT_IDLE) { + GLib.Idle.add(() => { + try { + expected.async_resume(); + } catch (GLib.Error err) { + critical( + "Async call already resumed: %s", err.message + ); + } + return GLib.Source.REMOVE; + }); + } + @yield = true; + } + return @yield; + } + + private inline bool check_boolean_call(ExpectedCall expected, + bool default_return) + throws GLib.Error { + check_for_exception(expected); + bool return_value = default_return; + if (expected.return_value != null) { + return_value = expected.return_value.get_boolean(); + } + return return_value; + } + + private inline R check_object_call(ExpectedCall expected, + R default_return) + throws GLib.Error { + check_for_exception(expected); + R? return_object = default_return; + if (expected.return_object != null) { + return_object = (R) expected.return_object; + } + return return_object; + } + + private inline R check_object_or_throw_call(ExpectedCall expected, + GLib.Error default_error) + throws GLib.Error { + check_for_exception(expected); + if (expected.return_object == null) { + throw default_error; + } + return expected.return_object; + } + + private inline void check_for_exception(ExpectedCall expected) + throws GLib.Error { + if (expected.throw_error != null) { + throw expected.throw_error; + } + } + }