From d042d43ae1f44c37334fd620ad1e5625f06aa88f Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 21 Sep 2012 10:23:23 +0200 Subject: [PATCH] gcr: Implement prompt-close in GcrSystemPrompt and GcrSystemPrompter * Properly relay the prompt-close signal from GcrSystemPrompter back to GcrSystemPrompt by firing the PromptDone callback method on the caller's DBus interface. * Make sure GcrSystemPrompt emits prompt-close appropriately for all the various paths that can close the prompt. * Add testing of the above, and changes in the mock prompter for this. https://bugzilla.gnome.org/show_bug.cgi?id=678611 --- docs/reference/gcr/gcr-sections.txt | 1 + gcr/gcr-base.symbols | 1 + gcr/gcr-mock-prompter.c | 44 ++++++++ gcr/gcr-mock-prompter.h | 2 + gcr/gcr-system-prompt.c | 212 +++++++++++++++++++++--------------- gcr/gcr-system-prompter.c | 58 ++++++++-- gcr/tests/frob-system-prompt.c | 3 + gcr/tests/test-system-prompt.c | 99 +++++++++++++++++ 8 files changed, 324 insertions(+), 96 deletions(-) diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt index 2b21ca9..b39923e 100644 --- a/docs/reference/gcr/gcr-sections.txt +++ b/docs/reference/gcr/gcr-sections.txt @@ -851,6 +851,7 @@ gcr_mock_prompter_expect_confirm_cancel gcr_mock_prompter_expect_confirm_ok gcr_mock_prompter_expect_password_cancel gcr_mock_prompter_expect_password_ok +gcr_mock_prompter_expect_close gcr_mock_prompter_get_delay_msec gcr_mock_prompter_set_delay_msec gcr_mock_prompter_is_expecting diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols index bcf7bfb..c794829 100644 --- a/gcr/gcr-base.symbols +++ b/gcr/gcr-base.symbols @@ -100,6 +100,7 @@ gcr_import_interaction_supplement gcr_import_interaction_supplement_async gcr_import_interaction_supplement_finish gcr_import_interaction_supplement_prep +gcr_mock_prompter_expect_close gcr_mock_prompter_expect_confirm_cancel gcr_mock_prompter_expect_confirm_ok gcr_mock_prompter_expect_password_cancel diff --git a/gcr/gcr-mock-prompter.c b/gcr/gcr-mock-prompter.c index 1ef31e0..564ed2d 100644 --- a/gcr/gcr-mock-prompter.c +++ b/gcr/gcr-mock-prompter.c @@ -88,6 +88,7 @@ struct _GcrMockPromptClass { }; typedef struct { + gboolean close; gboolean proceed; gchar *password; GList *properties; @@ -403,6 +404,17 @@ on_timeout_complete (gpointer data) return FALSE; } +static gboolean +on_timeout_complete_and_close (gpointer data) +{ + GSimpleAsyncResult *res = data; + GcrPrompt *prompt = GCR_PROMPT (g_async_result_get_source_object (data)); + g_simple_async_result_complete (res); + gcr_prompt_close (prompt); + g_object_unref (prompt); + return FALSE; +} + static void gcr_mock_prompt_confirm_async (GcrPrompt *prompt, GCancellable *cancellable, @@ -428,6 +440,10 @@ gcr_mock_prompt_confirm_async (GcrPrompt *prompt, g_critical ("password prompt requested, but not expected"); g_simple_async_result_set_op_res_gboolean (res, FALSE); + } else if (response->close) { + complete_func = on_timeout_complete_and_close; + g_simple_async_result_set_op_res_gboolean (res, FALSE); + } else if (response->password) { g_critical ("confirmation prompt requested, but password prompt expected"); g_simple_async_result_set_op_res_gboolean (res, FALSE); @@ -504,6 +520,10 @@ gcr_mock_prompt_password_async (GcrPrompt *prompt, g_critical ("password prompt requested, but not expected"); g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); + } else if (response->close) { + g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); + complete_func = on_timeout_complete_and_close; + } else if (!response->password) { g_critical ("password prompt requested, but confirmation prompt expected"); g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); @@ -798,6 +818,30 @@ gcr_mock_prompter_expect_password_cancel (void) } /** + * gcr_mock_prompter_expect_close: + * + * Queue an expected response on the mock prompter. + * + * Expects any prompt, and closes the prompt when it gets it. + */ +void +gcr_mock_prompter_expect_close (void) +{ + MockResponse *response; + + g_assert (running != NULL); + + g_mutex_lock (running->mutex); + + response = g_new0 (MockResponse, 1); + response->close = TRUE; + + g_queue_push_tail (&running->responses, response); + + g_mutex_unlock (running->mutex); +} + +/** * gcr_mock_prompter_is_expecting: * * Check if the mock prompter is expecting a response. This will be %TRUE diff --git a/gcr/gcr-mock-prompter.h b/gcr/gcr-mock-prompter.h index 43c53cb..3e2cf26 100644 --- a/gcr/gcr-mock-prompter.h +++ b/gcr/gcr-mock-prompter.h @@ -55,6 +55,8 @@ void gcr_mock_prompter_expect_password_ok (const gchar *p void gcr_mock_prompter_expect_password_cancel (void); +void gcr_mock_prompter_expect_close (void); + gboolean gcr_mock_prompter_is_expecting (void); G_END_DECLS diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c index b66e30e..640aa77 100644 --- a/gcr/gcr-system-prompt.c +++ b/gcr/gcr-system-prompt.c @@ -390,15 +390,100 @@ gcr_system_prompt_constructed (GObject *obj) } static void +on_prompter_stop_prompting (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = NULL; + GError *error = NULL; + GVariant *retval; + + retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (error != NULL) { + _gcr_debug ("failed to stop prompting: %s", egg_error_message (error)); + g_clear_error (&error); + } + + if (retval) + g_variant_unref (retval); + + if (user_data) { + async = G_SIMPLE_ASYNC_RESULT (user_data); + g_simple_async_result_complete (async); + g_object_unref (async); + } +} + +static void +perform_close (GcrSystemPrompt *self, + GSimpleAsyncResult *async, + GCancellable *cancellable) +{ + GSimpleAsyncResult *res; + CallClosure *closure; + gboolean called = FALSE; + gboolean closed; + + closed = self->pv->closed; + self->pv->closed = TRUE; + + if (!closed) + _gcr_debug ("closing prompt"); + + if (self->pv->pending) { + res = g_object_ref (self->pv->pending); + g_clear_object (&self->pv->pending); + closure = g_simple_async_result_get_op_res_gpointer (res); + g_cancellable_cancel (closure->cancellable); + g_simple_async_result_complete_in_idle (res); + g_object_unref (res); + } + + if (self->pv->prompt_registered) { + g_dbus_connection_unregister_object (self->pv->connection, + self->pv->prompt_registered); + self->pv->prompt_registered = 0; + } + + if (self->pv->begun_prompting) { + if (self->pv->connection && self->pv->prompt_path) { + _gcr_debug ("Calling the prompter %s method", GCR_DBUS_PROMPTER_METHOD_STOP); + g_dbus_connection_call (self->pv->connection, + self->pv->prompter_bus_name, + GCR_DBUS_PROMPTER_OBJECT_PATH, + GCR_DBUS_PROMPTER_INTERFACE, + GCR_DBUS_PROMPTER_METHOD_STOP, + g_variant_new ("(o)", self->pv->prompt_path), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, cancellable, + on_prompter_stop_prompting, + async ? g_object_ref (async) : NULL); + called = TRUE; + } + self->pv->begun_prompting = FALSE; + } + + g_free (self->pv->prompt_path); + self->pv->prompt_path = NULL; + + g_clear_object (&self->pv->connection); + + if (!called && async) + g_simple_async_result_complete_in_idle (async); + + /* Emit the signal if necessary, after closed */ + if (!closed) + gcr_prompt_close (GCR_PROMPT (self)); +} + +static void gcr_system_prompt_dispose (GObject *obj) { GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj); g_clear_object (&self->pv->exchange); - - _gcr_debug ("closing prompt asynchronously: %s", self->pv->prompt_path); - if (self->pv->connection) - gcr_system_prompt_close_async (self, NULL, NULL, NULL); + perform_close (self, NULL, NULL); g_hash_table_remove_all (self->pv->properties); g_hash_table_remove_all (self->pv->dirty_properties); @@ -559,17 +644,15 @@ prompt_method_done (GcrSystemPrompt *self, GDBusMethodInvocation *invocation, GVariant *parameters) { - GSimpleAsyncResult *res; - - g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (self->pv->pending)); - g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); - res = g_object_ref (self->pv->pending); - g_clear_object (&self->pv->pending); - g_simple_async_result_set_op_res_gpointer (res, NULL, NULL); - g_simple_async_result_complete (res); - g_object_unref (res); + /* + * At this point we're done prompting, and calling StopPrompting + * on the prompter is no longer necessary. It may have already been + * called, or the prompter may have stopped on its own accord. + */ + self->pv->begun_prompting = FALSE; + perform_close (self, NULL, NULL); } static void @@ -951,8 +1034,9 @@ on_perform_prompt_complete (GObject *source, retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (error != NULL) { + self->pv->pending = NULL; g_simple_async_result_take_error (res, error); - g_simple_async_result_complete_in_idle (res); + g_simple_async_result_complete (res); } if (retval) @@ -984,13 +1068,20 @@ perform_prompt_async (GcrSystemPrompt *self, return; } - _gcr_debug ("prompting for password"); - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, source_tag); closure = g_new0 (CallClosure, 1); closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free); + if (self->pv->closed) { + self->pv->last_response = g_strdup (GCR_DBUS_PROMPT_REPLY_NONE); + g_simple_async_result_complete_in_idle (res); + g_object_unref (res); + return; + } + + _gcr_debug ("prompting for password"); + exchange = gcr_system_prompt_get_secret_exchange (self); if (self->pv->received) sent = gcr_secret_exchange_send (exchange, NULL, 0); @@ -1107,12 +1198,29 @@ gcr_system_prompt_confirm_finish (GcrPrompt *prompt, } static void +gcr_system_prompt_real_close (GcrPrompt *prompt) +{ + GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt); + + /* + * Setting this before calling close_async allows us to prevent firing + * this signal again in a loop. + */ + + if (!self->pv->closed) { + self->pv->closed = TRUE; + perform_close (self, NULL, NULL); + } +} + +static void gcr_system_prompt_prompt_iface (GcrPromptIface *iface) { iface->prompt_password_async = gcr_system_prompt_password_async; iface->prompt_password_finish = gcr_system_prompt_password_finish; iface->prompt_confirm_async = gcr_system_prompt_confirm_async; iface->prompt_confirm_finish = gcr_system_prompt_confirm_finish; + iface->prompt_close = gcr_system_prompt_real_close; } /** @@ -1299,8 +1407,8 @@ gcr_system_prompt_open_for_prompter (const gchar *prompter_name, * @cancellable: an optional cancellation object * @error: location to place an error on failure * - * Close this prompt. After calling this function, no further methods may be - * called on this object. The prompt object is not unreferenced by this + * Close this prompt. After calling this function, no further prompts will + * succeed on this object. The prompt object is not unreferenced by this * function, and you must unreference it once done. * * This call may block, use the gcr_system_prompt_close_async() to perform @@ -1335,28 +1443,6 @@ gcr_system_prompt_close (GcrSystemPrompt *self, return result; } -static void -on_prompter_stop_prompting (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GError *error = NULL; - GVariant *retval; - - retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (error != NULL) { - _gcr_debug ("failed to stop prompting: %s", egg_error_message (error)); - g_clear_error (&error); - } - - if (retval) - g_variant_unref (retval); - - g_simple_async_result_complete (res); - g_object_unref (res); -} - /** * gcr_system_prompt_close_async: * @self: the prompt @@ -1378,25 +1464,9 @@ gcr_system_prompt_close_async (GcrSystemPrompt *self, { GSimpleAsyncResult *res; CallClosure *closure; - gboolean called = FALSE; g_return_if_fail (GCR_SYSTEM_PROMPT (self)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - g_return_if_fail (self->pv->connection != NULL); - g_return_if_fail (self->pv->prompt_path != NULL); - g_return_if_fail (self->pv->closed == FALSE); - - _gcr_debug ("closing prompt"); - self->pv->closed = TRUE; - - if (self->pv->pending) { - res = g_object_ref (self->pv->pending); - g_clear_object (&self->pv->pending); - closure = g_simple_async_result_get_op_res_gpointer (res); - g_cancellable_cancel (closure->cancellable); - g_simple_async_result_complete_in_idle (res); - g_object_unref (res); - } res = g_simple_async_result_new (NULL, callback, user_data, gcr_system_prompt_close_async); @@ -1407,36 +1477,8 @@ gcr_system_prompt_close_async (GcrSystemPrompt *self, g_main_context_ref (closure->context); g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free); - if (self->pv->prompt_registered) { - g_dbus_connection_unregister_object (self->pv->connection, - self->pv->prompt_registered); - self->pv->prompt_registered = 0; - } + perform_close (self, res, closure->cancellable); - if (self->pv->begun_prompting) { - if (self->pv->connection) { - g_dbus_connection_call (self->pv->connection, - self->pv->prompter_bus_name, - GCR_DBUS_PROMPTER_OBJECT_PATH, - GCR_DBUS_PROMPTER_INTERFACE, - GCR_DBUS_PROMPTER_METHOD_STOP, - g_variant_new ("(o)", self->pv->prompt_path), - G_VARIANT_TYPE ("()"), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, closure->cancellable, - on_prompter_stop_prompting, - g_object_ref (res)); - called = TRUE; - } - } - - g_free (self->pv->prompt_path); - self->pv->prompt_path = NULL; - - g_clear_object (&self->pv->connection); - - if (!called) - g_simple_async_result_complete_in_idle (res); g_object_unref (res); } diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c index fb03ec8..ba16dcc 100644 --- a/gcr/gcr-system-prompter.c +++ b/gcr/gcr-system-prompter.c @@ -121,6 +121,8 @@ typedef struct { GHashTable *changed; GcrSecretExchange *exchange; gboolean received; + gboolean closed; + guint close_sig; } ActivePrompt; static void prompt_send_ready (ActivePrompt *active, @@ -151,6 +153,14 @@ on_prompt_notify (GObject *object, g_hash_table_replace (active->changed, key, key); } +static void +on_prompt_close (GcrPrompt *prompt, + gpointer user_data) +{ + ActivePrompt *active = user_data; + prompt_stop_prompting (active->prompter, active->callback, TRUE, FALSE); +} + static Callback * callback_dup (Callback *original) { @@ -195,9 +205,13 @@ active_prompt_unref (gpointer data) ActivePrompt *active = data; if (g_atomic_int_dec_and_test (&active->refs)) { + callback_free (active->callback); g_object_unref (active->prompter); g_object_unref (active->cancellable); - g_signal_handlers_disconnect_by_func (active->prompt, on_prompt_notify, active); + if (g_signal_handler_is_connected (active->prompt, active->notify_sig)) + g_signal_handler_disconnect (active->prompt, active->notify_sig); + if (g_signal_handler_is_connected (active->prompt, active->close_sig)) + g_signal_handler_disconnect (active->prompt, active->close_sig); g_object_unref (active->prompt); g_hash_table_destroy (active->changed); if (active->exchange) @@ -221,17 +235,15 @@ active_prompt_create (GcrSystemPrompter *self, ActivePrompt *active; active = g_slice_new0 (ActivePrompt); - if (!g_hash_table_lookup_extended (self->pv->callbacks, lookup, - (gpointer *)&active->callback, NULL)) - g_return_val_if_reached (NULL); - active->refs = 1; + active->callback = callback_dup (lookup); active->prompter = g_object_ref (self); active->cancellable = g_cancellable_new (); g_signal_emit (self, signals[NEW_PROMPT], 0, &active->prompt); g_return_val_if_fail (active->prompt != NULL, NULL); active->notify_sig = g_signal_connect (active->prompt, "notify", G_CALLBACK (on_prompt_notify), active); + active->close_sig = g_signal_connect (active->prompt, "prompt-close", G_CALLBACK (on_prompt_close), active); active->changed = g_hash_table_new (g_direct_hash, g_direct_equal); /* Insert us into the active hash table */ @@ -481,11 +493,26 @@ prompt_stop_prompting (GcrSystemPrompter *self, { ActivePrompt *active; GVariant *retval; + gpointer watch; + + _gcr_debug ("stopping prompting for operation %s@%s", + callback->path, callback->name); /* Get a pointer to our actual callback */ if (!g_hash_table_lookup_extended (self->pv->callbacks, callback, - (gpointer *)&callback, NULL)) + (gpointer *)&callback, &watch)) { + _gcr_debug ("couldn't find the callback for prompting operation %s@%s", + callback->path, callback->name); return; + } + + /* + * We remove these from the callbacks hash table so that we don't + * do this stuff more than once. However we still need the callback + * to be valid. + */ + if (!g_hash_table_steal (self->pv->callbacks, callback)) + g_assert_not_reached (); /* Removed from the waiting queue */ g_queue_remove (&self->pv->waiting, callback); @@ -493,16 +520,19 @@ prompt_stop_prompting (GcrSystemPrompter *self, /* Close any active prompt */ active = g_hash_table_lookup (self->pv->active, callback); if (active != NULL) { + active_prompt_ref (active); + g_hash_table_remove (self->pv->active, callback); + if (!active->ready) { _gcr_debug ("cancelling active prompting operation for %s@%s", callback->path, callback->name); g_cancellable_cancel (active->cancellable); } - _gcr_debug ("disposing the prompt"); - + _gcr_debug ("closing the prompt"); + gcr_prompt_close (active->prompt); g_object_run_dispose (G_OBJECT (active->prompt)); - g_hash_table_remove (self->pv->active, callback); + active_prompt_unref (active); } /* Notify the caller */ @@ -540,8 +570,14 @@ prompt_stop_prompting (GcrSystemPrompter *self, -1, NULL, NULL, NULL); } - /* And all traces gone, including watch */ - g_hash_table_remove (self->pv->callbacks, callback); + /* + * And all traces gone, including watch. We stole these values from + * the callbacks hashtable above. Now free them + */ + + callback_free (callback); + unwatch_name (watch); + g_object_notify (G_OBJECT (self), "prompting"); } diff --git a/gcr/tests/frob-system-prompt.c b/gcr/tests/frob-system-prompt.c index 39919b3..b743adf 100644 --- a/gcr/tests/frob-system-prompt.c +++ b/gcr/tests/frob-system-prompt.c @@ -25,6 +25,8 @@ #include "gcr/gcr.h" +#include "egg/egg-testing.h" + #include #include @@ -67,6 +69,7 @@ on_prompt_clicked (GtkToolButton *button, g_print ("password: %s\n", password); g_object_unref (prompt); + egg_assert_not_object (prompt); } static gboolean diff --git a/gcr/tests/test-system-prompt.c b/gcr/tests/test-system-prompt.c index d0450b5..0d48124 100644 --- a/gcr/tests/test-system-prompt.c +++ b/gcr/tests/test-system-prompt.c @@ -513,6 +513,15 @@ test_prompt_close (Test *test, } static void +on_prompt_close (GcrPrompt *prompt, + gpointer user_data) +{ + gboolean *prompt_closed = (gboolean *)user_data; + g_assert (*prompt_closed == FALSE); + *prompt_closed = TRUE; +} + +static void test_close_cancels (Test *test, gconstpointer unused) { @@ -520,6 +529,7 @@ test_close_cancels (Test *test, GError *error = NULL; const gchar *password = NULL; GAsyncResult *result = NULL; + gboolean prompt_closed; gcr_mock_prompter_set_delay_msec (3000); gcr_mock_prompter_expect_password_ok ("booo", NULL); @@ -528,11 +538,15 @@ test_close_cancels (Test *test, g_assert_no_error (error); g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); + prompt_closed = FALSE; + g_signal_connect_after (prompt, "prompt-close", G_CALLBACK (on_prompt_close), &prompt_closed); + gcr_prompt_password_async (prompt, NULL, on_async_result, &result); gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, &error); g_assert_no_error (error); + g_assert (prompt_closed == TRUE); egg_test_wait (); password = gcr_prompt_password_finish (prompt, result, &error); @@ -544,6 +558,89 @@ test_close_cancels (Test *test, egg_assert_not_object (prompt); } +static void +test_close_from_prompter (Test *test, + gconstpointer unused) +{ + GcrPrompt *prompt; + GError *error = NULL; + gboolean ret; + const gchar *password; + gboolean prompt_closed; + + gcr_mock_prompter_expect_close (); + + prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error); + g_assert_no_error (error); + g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); + + prompt_closed = FALSE; + g_signal_connect_after (prompt, "prompt-close", G_CALLBACK (on_prompt_close), &prompt_closed); + + ret = gcr_prompt_confirm_run (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (ret == GCR_PROMPT_REPLY_CANCEL); + + /* The prompt should be closed now, these shouldn't reach the mock prompter */ + + while (!prompt_closed) + g_main_context_iteration (NULL, TRUE); + + ret = gcr_prompt_confirm_run (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (ret == GCR_PROMPT_REPLY_CANCEL); + + password = gcr_prompt_password_run (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (password == NULL); + + g_object_unref (prompt); + egg_assert_not_object (prompt); +} + +static void +test_after_close_dismisses (Test *test, + gconstpointer unused) +{ + GcrPrompt *prompt; + GError *error = NULL; + gboolean ret; + const gchar *password; + gboolean prompt_closed; + + gcr_mock_prompter_expect_confirm_ok (NULL); + + prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error); + g_assert_no_error (error); + g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); + + prompt_closed = FALSE; + g_signal_connect_after (prompt, "prompt-close", G_CALLBACK (on_prompt_close), &prompt_closed); + + + ret = gcr_prompt_confirm_run (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (ret == GCR_PROMPT_REPLY_CONTINUE); + + gcr_prompt_close (prompt); + g_assert (prompt_closed); + + /* These should never even reach the mock prompter */ + + ret = gcr_prompt_confirm_run (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (ret == GCR_PROMPT_REPLY_CANCEL); + + password = gcr_prompt_password_run (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (password == NULL); + + while (g_main_context_iteration (NULL, FALSE)); + + g_object_unref (prompt); + egg_assert_not_object (prompt); +} + int main (int argc, char **argv) { @@ -568,6 +665,8 @@ main (int argc, char **argv) g_test_add ("/gcr/system-prompt/properties-reset", Test, NULL, setup, test_prompt_properties_reset, teardown); g_test_add ("/gcr/system-prompt/close", Test, NULL, setup, test_prompt_close, teardown); g_test_add ("/gcr/system-prompt/close-cancels", Test, NULL, setup, test_close_cancels, teardown); + g_test_add ("/gcr/system-prompt/after-close-dismisses", Test, NULL, setup, test_after_close_dismisses, teardown); + g_test_add ("/gcr/system-prompt/close-from-prompter", Test, NULL, setup, test_close_from_prompter, teardown); return egg_tests_run_with_loop (); } -- 2.7.4