Blame gcr/gcr-mock-prompter.c

Packit b00eeb
/*
Packit b00eeb
 * gnome-keyring
Packit b00eeb
 *
Packit b00eeb
 * Copyright (C) 2011 Collabora Ltd.
Packit b00eeb
 *
Packit b00eeb
 * This program is free software; you can redistribute it and/or modify
Packit b00eeb
 * it under the terms of the GNU Lesser General Public License as
Packit b00eeb
 * published by the Free Software Foundation; either version 2.1 of
Packit b00eeb
 * the License, or (at your option) any later version.
Packit b00eeb
 *
Packit b00eeb
 * This program is distributed in the hope that it will be useful, but
Packit b00eeb
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b00eeb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit b00eeb
 * Lesser General Public License for more details.
Packit b00eeb
 *
Packit b00eeb
 * You should have received a copy of the GNU Lesser General Public
Packit b00eeb
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit b00eeb
 *
Packit b00eeb
 * Author: Stef Walter <stfew@collabora.co.uk>
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
#include "config.h"
Packit b00eeb
Packit b00eeb
#include "gcr-mock-prompter.h"
Packit b00eeb
#include "gcr-prompt.h"
Packit b00eeb
Packit b00eeb
#include "egg/egg-error.h"
Packit b00eeb
Packit b00eeb
#include <gobject/gvaluecollector.h>
Packit b00eeb
Packit b00eeb
#include <string.h>
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * SECTION:gcr-mock-prompter
Packit b00eeb
 * @title: GcrMockPrompter
Packit b00eeb
 * @short_description: a mock GcrSystemPrompter for testing
Packit b00eeb
 *
Packit b00eeb
 * A mock GcrSystemPrompter used for testing against.
Packit b00eeb
 *
Packit b00eeb
 * Use gcr_mock_prompter_start() to start the mock prompter in another
Packit b00eeb
 * thread. The returned string is the dbus address of the mock prompter.
Packit b00eeb
 * You can pass this to gcr_system_prompt_open() as the prompter bus name.
Packit b00eeb
 *
Packit b00eeb
 * Use the gcr_mock_prompter_expect_confirm_ok() function and friends before
Packit b00eeb
 * prompting to verify that the prompts are displayed as expected, and to
Packit b00eeb
 * provide a response.
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
GType   _gcr_mock_prompt_get_type       (void) G_GNUC_CONST;
Packit b00eeb
#define GCR_TYPE_MOCK_PROMPT            (_gcr_mock_prompt_get_type ())
Packit b00eeb
#define GCR_MOCK_PROMPT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MOCK_PROMPT, GcrMockPrompt))
Packit b00eeb
#define GCR_IS_MOCK_PROMPT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MOCK_PROMPT))
Packit b00eeb
#define GCR_IS_MOCK_PROMPT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MOCK_PROMPT))
Packit b00eeb
#define GCR_MOCK_PROMPT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MOCK_PROMPT, GcrMockPromptClass))
Packit b00eeb
#define GCR_MOCK_PROMPT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MOCK_PROMPT, GcrMockPromptClass))
Packit b00eeb
Packit b00eeb
typedef struct _GcrMockPrompt GcrMockPrompt;
Packit b00eeb
typedef struct _GcrMockPromptClass GcrMockPromptClass;
Packit b00eeb
typedef struct _GcrMockPromptPrivate GcrMockPromptPrivate;
Packit b00eeb
Packit b00eeb
enum {
Packit b00eeb
	PROP_0,
Packit b00eeb
Packit b00eeb
	PROP_TITLE,
Packit b00eeb
	PROP_MESSAGE,
Packit b00eeb
	PROP_DESCRIPTION,
Packit b00eeb
	PROP_WARNING,
Packit b00eeb
	PROP_PASSWORD_NEW,
Packit b00eeb
	PROP_PASSWORD_STRENGTH,
Packit b00eeb
	PROP_CHOICE_LABEL,
Packit b00eeb
	PROP_CHOICE_CHOSEN,
Packit b00eeb
	PROP_CALLER_WINDOW,
Packit b00eeb
	PROP_CONTINUE_LABEL,
Packit b00eeb
	PROP_CANCEL_LABEL,
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
struct _GcrMockPrompt {
Packit b00eeb
	GObject parent;
Packit b00eeb
	GHashTable *properties;
Packit b00eeb
	gboolean disposed;
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
struct _GcrMockPromptClass {
Packit b00eeb
	GObjectClass parent_class;
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
typedef struct {
Packit b00eeb
	gboolean close;
Packit b00eeb
	gboolean proceed;
Packit b00eeb
	gchar *password;
Packit b00eeb
	GList *properties;
Packit b00eeb
} MockResponse;
Packit b00eeb
Packit b00eeb
typedef struct {
Packit b00eeb
	/* Owned by the calling thread */
Packit b00eeb
	GMutex *mutex;
Packit b00eeb
	GCond *start_cond;
Packit b00eeb
	GThread *thread;
Packit b00eeb
Packit b00eeb
	guint delay_msec;
Packit b00eeb
	GQueue responses;
Packit b00eeb
Packit b00eeb
	/* Owned by the prompter thread*/
Packit b00eeb
	GcrSystemPrompter *prompter;
Packit b00eeb
	GDBusConnection *connection;
Packit b00eeb
	GMainLoop *loop;
Packit b00eeb
} ThreadData;
Packit b00eeb
Packit b00eeb
static gint prompts_a_prompting = 0;
Packit b00eeb
static ThreadData *running = NULL;
Packit b00eeb
Packit b00eeb
static void    gcr_mock_prompt_iface     (GcrPromptIface *iface);
Packit b00eeb
Packit b00eeb
G_DEFINE_TYPE_WITH_CODE (GcrMockPrompt, _gcr_mock_prompt, G_TYPE_OBJECT,
Packit b00eeb
                         G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gcr_mock_prompt_iface);
Packit b00eeb
);
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
mock_property_free (gpointer data)
Packit b00eeb
{
Packit b00eeb
	GParameter *param = data;
Packit b00eeb
	g_value_unset (&param->value);
Packit b00eeb
	g_free (param);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
mock_response_free (gpointer data)
Packit b00eeb
{
Packit b00eeb
	MockResponse *response = data;
Packit b00eeb
Packit b00eeb
	if (response == NULL)
Packit b00eeb
		return;
Packit b00eeb
Packit b00eeb
	g_free (response->password);
Packit b00eeb
	g_list_free_full (response->properties, mock_property_free);
Packit b00eeb
	g_free (response);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
blank_string_property (GHashTable *properties,
Packit b00eeb
                       const gchar *property)
Packit b00eeb
{
Packit b00eeb
	GParameter *param;
Packit b00eeb
Packit b00eeb
	param = g_new0 (GParameter, 1);
Packit b00eeb
	param->name = property;
Packit b00eeb
	g_value_init (&param->value, G_TYPE_STRING);
Packit b00eeb
	g_value_set_string (&param->value, "");
Packit b00eeb
	g_hash_table_insert (properties, (gpointer)param->name, param);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
blank_boolean_property (GHashTable *properties,
Packit b00eeb
                        const gchar *property)
Packit b00eeb
{
Packit b00eeb
	GParameter *param;
Packit b00eeb
Packit b00eeb
	param = g_new0 (GParameter, 1);
Packit b00eeb
	param->name = property;
Packit b00eeb
	g_value_init (&param->value, G_TYPE_BOOLEAN);
Packit b00eeb
	g_value_set_boolean (&param->value, FALSE);
Packit b00eeb
	g_hash_table_insert (properties, (gpointer)param->name, param);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
blank_int_property (GHashTable *properties,
Packit b00eeb
                    const gchar *property)
Packit b00eeb
{
Packit b00eeb
	GParameter *param;
Packit b00eeb
Packit b00eeb
	param = g_new0 (GParameter, 1);
Packit b00eeb
	param->name = property;
Packit b00eeb
	g_value_init (&param->value, G_TYPE_INT);
Packit b00eeb
	g_value_set_int (&param->value, 0);
Packit b00eeb
	g_hash_table_insert (properties, (gpointer)param->name, param);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
_gcr_mock_prompt_init (GcrMockPrompt *self)
Packit b00eeb
{
Packit b00eeb
	g_atomic_int_add (&prompts_a_prompting, 1);
Packit b00eeb
Packit b00eeb
	self->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
Packit b00eeb
	                                          NULL, mock_property_free);
Packit b00eeb
Packit b00eeb
	blank_string_property (self->properties, "title");
Packit b00eeb
	blank_string_property (self->properties, "message");
Packit b00eeb
	blank_string_property (self->properties, "description");
Packit b00eeb
	blank_string_property (self->properties, "warning");
Packit b00eeb
	blank_string_property (self->properties, "choice-label");
Packit b00eeb
	blank_string_property (self->properties, "caller-window");
Packit b00eeb
	blank_string_property (self->properties, "continue-label");
Packit b00eeb
	blank_string_property (self->properties, "cancel-label");
Packit b00eeb
Packit b00eeb
	blank_boolean_property (self->properties, "choice-chosen");
Packit b00eeb
	blank_boolean_property (self->properties, "password-new");
Packit b00eeb
Packit b00eeb
	blank_int_property (self->properties, "password-strength");
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
_gcr_mock_prompt_set_property (GObject *obj,
Packit b00eeb
                              guint prop_id,
Packit b00eeb
                              const GValue *value,
Packit b00eeb
                              GParamSpec *pspec)
Packit b00eeb
{
Packit b00eeb
	GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
Packit b00eeb
	GParameter *param;
Packit b00eeb
Packit b00eeb
	switch (prop_id) {
Packit b00eeb
	case PROP_TITLE:
Packit b00eeb
	case PROP_MESSAGE:
Packit b00eeb
	case PROP_DESCRIPTION:
Packit b00eeb
	case PROP_WARNING:
Packit b00eeb
	case PROP_PASSWORD_NEW:
Packit b00eeb
	case PROP_CHOICE_LABEL:
Packit b00eeb
	case PROP_CHOICE_CHOSEN:
Packit b00eeb
	case PROP_CALLER_WINDOW:
Packit b00eeb
	case PROP_CONTINUE_LABEL:
Packit b00eeb
	case PROP_CANCEL_LABEL:
Packit b00eeb
		param = g_new0 (GParameter, 1);
Packit b00eeb
		param->name = pspec->name;
Packit b00eeb
		g_value_init (&param->value, pspec->value_type);
Packit b00eeb
		g_value_copy (value, &param->value);
Packit b00eeb
		g_hash_table_replace (self->properties, (gpointer)param->name, param);
Packit b00eeb
		g_object_notify (G_OBJECT (self), param->name);
Packit b00eeb
		break;
Packit b00eeb
	default:
Packit b00eeb
		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
Packit b00eeb
		break;
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
_gcr_mock_prompt_get_property (GObject *obj,
Packit b00eeb
                              guint prop_id,
Packit b00eeb
                              GValue *value,
Packit b00eeb
                              GParamSpec *pspec)
Packit b00eeb
{
Packit b00eeb
	GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
Packit b00eeb
	GParameter *param;
Packit b00eeb
Packit b00eeb
	switch (prop_id) {
Packit b00eeb
	case PROP_TITLE:
Packit b00eeb
	case PROP_MESSAGE:
Packit b00eeb
	case PROP_DESCRIPTION:
Packit b00eeb
	case PROP_WARNING:
Packit b00eeb
	case PROP_PASSWORD_NEW:
Packit b00eeb
	case PROP_PASSWORD_STRENGTH:
Packit b00eeb
	case PROP_CHOICE_LABEL:
Packit b00eeb
	case PROP_CHOICE_CHOSEN:
Packit b00eeb
	case PROP_CALLER_WINDOW:
Packit b00eeb
	case PROP_CONTINUE_LABEL:
Packit b00eeb
	case PROP_CANCEL_LABEL:
Packit b00eeb
		param = g_hash_table_lookup (self->properties, pspec->name);
Packit b00eeb
		g_return_if_fail (param != NULL);
Packit b00eeb
		g_value_copy (&param->value, value);
Packit b00eeb
		break;
Packit b00eeb
	default:
Packit b00eeb
		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
Packit b00eeb
		break;
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
_gcr_mock_prompt_dispose (GObject *obj)
Packit b00eeb
{
Packit b00eeb
	GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
Packit b00eeb
Packit b00eeb
	if (!self->disposed) {
Packit b00eeb
		g_atomic_int_add (&prompts_a_prompting, -1);
Packit b00eeb
		self->disposed = TRUE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	G_OBJECT_CLASS (_gcr_mock_prompt_parent_class)->dispose (obj);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
_gcr_mock_prompt_finalize (GObject *obj)
Packit b00eeb
{
Packit b00eeb
	GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
Packit b00eeb
Packit b00eeb
	g_hash_table_destroy(self->properties);
Packit b00eeb
Packit b00eeb
	G_OBJECT_CLASS (_gcr_mock_prompt_parent_class)->finalize (obj);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
value_equal (const GValue *a, const GValue *b)
Packit b00eeb
{
Packit b00eeb
	gboolean ret = FALSE;
Packit b00eeb
Packit b00eeb
	g_assert (G_VALUE_TYPE (a) == G_VALUE_TYPE (b));
Packit b00eeb
Packit b00eeb
	switch (G_VALUE_TYPE (a)) {
Packit b00eeb
	case G_TYPE_BOOLEAN:
Packit b00eeb
		ret = (g_value_get_boolean (a) == g_value_get_boolean (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_UCHAR:
Packit b00eeb
		ret = (g_value_get_uchar (a) == g_value_get_uchar (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_INT:
Packit b00eeb
		ret = (g_value_get_int (a) == g_value_get_int (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_UINT:
Packit b00eeb
		ret = (g_value_get_uint (a) == g_value_get_uint (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_INT64:
Packit b00eeb
		ret = (g_value_get_int64 (a) == g_value_get_int64 (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_UINT64:
Packit b00eeb
		ret = (g_value_get_uint64 (a) == g_value_get_uint64 (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_DOUBLE:
Packit b00eeb
		ret = (g_value_get_double (a) == g_value_get_double (b));
Packit b00eeb
		break;
Packit b00eeb
	case G_TYPE_STRING:
Packit b00eeb
		ret = (g_strcmp0 (g_value_get_string (a), g_value_get_string (b)) == 0);
Packit b00eeb
		break;
Packit b00eeb
	default:
Packit b00eeb
		g_critical ("no support for comparing of type %s", g_type_name (G_VALUE_TYPE (a)));
Packit b00eeb
		break;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return ret;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
prompt_set_or_check_properties (GcrMockPrompt *self,
Packit b00eeb
                                GList *properties)
Packit b00eeb
{
Packit b00eeb
	GValue value = G_VALUE_INIT;
Packit b00eeb
	GObjectClass *object_class;
Packit b00eeb
	GParameter *param;
Packit b00eeb
	GParamSpec *spec;
Packit b00eeb
	GList *l;
Packit b00eeb
Packit b00eeb
	object_class = G_OBJECT_GET_CLASS (self);
Packit b00eeb
	for (l = properties; l != NULL; l = g_list_next (l)) {
Packit b00eeb
		param = l->data;
Packit b00eeb
Packit b00eeb
		spec = g_object_class_find_property (object_class, param->name);
Packit b00eeb
		g_assert (spec != NULL);
Packit b00eeb
Packit b00eeb
		/* For these we set the value */
Packit b00eeb
		if (g_str_equal (param->name, "choice-chosen")) {
Packit b00eeb
			g_object_set_property (G_OBJECT (self), param->name, &param->value);
Packit b00eeb
Packit b00eeb
		/* For others we check that the value is correct */
Packit b00eeb
		} else {
Packit b00eeb
			g_value_init (&value, G_VALUE_TYPE (&param->value));
Packit b00eeb
			g_object_get_property (G_OBJECT (self), param->name, &value);
Packit b00eeb
			if (!value_equal (&value, &param->value)) {
Packit b00eeb
				gchar *expected = g_strdup_value_contents (&param->value);
Packit b00eeb
				gchar *actual = g_strdup_value_contents (&value);
Packit b00eeb
				g_critical ("expected prompt property '%s' to be %s, but it "
Packit b00eeb
				            "is instead %s", param->name, expected, actual);
Packit b00eeb
				g_free (expected);
Packit b00eeb
				g_free (actual);
Packit b00eeb
			}
Packit b00eeb
			g_value_unset (&value);
Packit b00eeb
		}
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
_gcr_mock_prompt_class_init (GcrMockPromptClass *klass)
Packit b00eeb
{
Packit b00eeb
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit b00eeb
Packit b00eeb
	gobject_class->get_property = _gcr_mock_prompt_get_property;
Packit b00eeb
	gobject_class->set_property = _gcr_mock_prompt_set_property;
Packit b00eeb
	gobject_class->dispose = _gcr_mock_prompt_dispose;
Packit b00eeb
	gobject_class->finalize = _gcr_mock_prompt_finalize;
Packit b00eeb
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_TITLE, "title");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CONTINUE_LABEL, "continue-label");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CANCEL_LABEL, "cancel-label");
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
on_timeout_complete (gpointer data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res = data;
Packit b00eeb
	g_simple_async_result_complete (res);
Packit b00eeb
	return FALSE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
on_timeout_complete_and_close (gpointer data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res = data;
Packit b00eeb
	GcrPrompt *prompt = GCR_PROMPT (g_async_result_get_source_object (data));
Packit b00eeb
	g_simple_async_result_complete (res);
Packit b00eeb
	gcr_prompt_close (prompt);
Packit b00eeb
	g_object_unref (prompt);
Packit b00eeb
	return FALSE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
destroy_unref_source (gpointer source)
Packit b00eeb
{
Packit b00eeb
	if (!g_source_is_destroyed (source))
Packit b00eeb
		g_source_destroy (source);
Packit b00eeb
	g_source_unref (source);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_mock_prompt_confirm_async (GcrPrompt *prompt,
Packit b00eeb
                               GCancellable *cancellable,
Packit b00eeb
                               GAsyncReadyCallback callback,
Packit b00eeb
                               gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrMockPrompt *self = GCR_MOCK_PROMPT (prompt);
Packit b00eeb
	GSourceFunc complete_func = on_timeout_complete;
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	MockResponse *response;
Packit b00eeb
	GSource *source;
Packit b00eeb
	guint delay_msec;
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
	delay_msec = running->delay_msec;
Packit b00eeb
	response = g_queue_pop_head (&running->responses);
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
Packit b00eeb
	res = g_simple_async_result_new (G_OBJECT (prompt), callback, user_data,
Packit b00eeb
	                                 gcr_mock_prompt_confirm_async);
Packit b00eeb
Packit b00eeb
	if (response == NULL) {
Packit b00eeb
		g_critical ("password prompt requested, but not expected");
Packit b00eeb
		g_simple_async_result_set_op_res_gboolean (res, FALSE);
Packit b00eeb
Packit b00eeb
	} else if (response->close) {
Packit b00eeb
		complete_func = on_timeout_complete_and_close;
Packit b00eeb
		g_simple_async_result_set_op_res_gboolean (res, FALSE);
Packit b00eeb
Packit b00eeb
	} else if (response->password) {
Packit b00eeb
		g_critical ("confirmation prompt requested, but password prompt expected");
Packit b00eeb
		g_simple_async_result_set_op_res_gboolean (res, FALSE);
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		prompt_set_or_check_properties (self, response->properties);
Packit b00eeb
		g_simple_async_result_set_op_res_gboolean (res, response->proceed);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (delay_msec > 0)
Packit b00eeb
		source = g_timeout_source_new (delay_msec);
Packit b00eeb
	else
Packit b00eeb
		source = g_idle_source_new ();
Packit b00eeb
Packit b00eeb
	g_source_set_callback (source, complete_func, g_object_ref (res), g_object_unref);
Packit b00eeb
	g_source_attach (source, g_main_context_get_thread_default ());
Packit b00eeb
	g_object_set_data_full (G_OBJECT (self), "delay-source", source, destroy_unref_source);
Packit b00eeb
Packit b00eeb
	mock_response_free (response);
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GcrPromptReply
Packit b00eeb
gcr_mock_prompt_confirm_finish (GcrPrompt *prompt,
Packit b00eeb
                                GAsyncResult *result,
Packit b00eeb
                                GError **error)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
Packit b00eeb
	                      gcr_mock_prompt_confirm_async), GCR_PROMPT_REPLY_CANCEL);
Packit b00eeb
Packit b00eeb
	return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)) ?
Packit b00eeb
	               GCR_PROMPT_REPLY_CONTINUE : GCR_PROMPT_REPLY_CANCEL;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
ensure_password_strength (GcrMockPrompt *self,
Packit b00eeb
                          const gchar *password)
Packit b00eeb
{
Packit b00eeb
	GParameter *param;
Packit b00eeb
	gint strength;
Packit b00eeb
Packit b00eeb
	strength = strlen (password) > 0 ? 1 : 0;
Packit b00eeb
	param = g_new0 (GParameter, 1);
Packit b00eeb
	param->name = "password-strength";
Packit b00eeb
	g_value_init (&param->value, G_TYPE_INT);
Packit b00eeb
	g_value_set_int (&param->value, strength);
Packit b00eeb
	g_hash_table_replace (self->properties, (gpointer)param->name, param);
Packit b00eeb
	g_object_notify (G_OBJECT (self), param->name);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_mock_prompt_password_async (GcrPrompt *prompt,
Packit b00eeb
                                GCancellable *cancellable,
Packit b00eeb
                                GAsyncReadyCallback callback,
Packit b00eeb
                                gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrMockPrompt *self = GCR_MOCK_PROMPT (prompt);
Packit b00eeb
	GSourceFunc complete_func = on_timeout_complete;
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	MockResponse *response;
Packit b00eeb
	GSource *source;
Packit b00eeb
	guint delay_msec;
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
	delay_msec = running->delay_msec;
Packit b00eeb
	response = g_queue_pop_head (&running->responses);
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
Packit b00eeb
	res = g_simple_async_result_new (G_OBJECT (prompt), callback, user_data,
Packit b00eeb
	                                 gcr_mock_prompt_password_async);
Packit b00eeb
Packit b00eeb
	if (response == NULL) {
Packit b00eeb
		g_critical ("password prompt requested, but not expected");
Packit b00eeb
		g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
Packit b00eeb
Packit b00eeb
	} else if (response->close) {
Packit b00eeb
		g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
Packit b00eeb
		complete_func = on_timeout_complete_and_close;
Packit b00eeb
Packit b00eeb
	} else if (!response->password) {
Packit b00eeb
		g_critical ("password prompt requested, but confirmation prompt expected");
Packit b00eeb
		g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
Packit b00eeb
Packit b00eeb
	} else if (!response->proceed) {
Packit b00eeb
		prompt_set_or_check_properties (self, response->properties);
Packit b00eeb
		g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		ensure_password_strength (self, response->password);
Packit b00eeb
		prompt_set_or_check_properties (self, response->properties);
Packit b00eeb
		g_simple_async_result_set_op_res_gpointer (res, response->password, g_free);
Packit b00eeb
		response->password = NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	mock_response_free (response);
Packit b00eeb
Packit b00eeb
	if (delay_msec > 0)
Packit b00eeb
		source = g_timeout_source_new (delay_msec);
Packit b00eeb
	else
Packit b00eeb
		source = g_idle_source_new ();
Packit b00eeb
Packit b00eeb
	g_source_set_callback (source, complete_func, g_object_ref (res), g_object_unref);
Packit b00eeb
	g_source_attach (source, g_main_context_get_thread_default ());
Packit b00eeb
	g_object_set_data_full (G_OBJECT (self), "delay-source", source, destroy_unref_source);
Packit b00eeb
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
Packit b00eeb
static const gchar *
Packit b00eeb
gcr_mock_prompt_password_finish (GcrPrompt *prompt,
Packit b00eeb
                                 GAsyncResult *result,
Packit b00eeb
                                 GError **error)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
Packit b00eeb
	                      gcr_mock_prompt_password_async), NULL);
Packit b00eeb
Packit b00eeb
	return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
Packit b00eeb
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_mock_prompt_iface (GcrPromptIface *iface)
Packit b00eeb
{
Packit b00eeb
	iface->prompt_confirm_async = gcr_mock_prompt_confirm_async;
Packit b00eeb
	iface->prompt_confirm_finish = gcr_mock_prompt_confirm_finish;
Packit b00eeb
	iface->prompt_password_async = gcr_mock_prompt_password_async;
Packit b00eeb
	iface->prompt_password_finish = gcr_mock_prompt_password_finish;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GList *
Packit b00eeb
build_properties (GObjectClass *object_class,
Packit b00eeb
                  const gchar *first_property,
Packit b00eeb
                  va_list var_args)
Packit b00eeb
{
Packit b00eeb
	GList *result = NULL;
Packit b00eeb
	const gchar *name;
Packit b00eeb
Packit b00eeb
	name = first_property;
Packit b00eeb
	while (name) {
Packit b00eeb
		GValue value = G_VALUE_INIT;
Packit b00eeb
		GParameter *parameter;
Packit b00eeb
		GParamSpec *spec;
Packit b00eeb
		gchar *error = NULL;
Packit b00eeb
Packit b00eeb
		spec = g_object_class_find_property (object_class, name);
Packit b00eeb
		if (spec == NULL) {
Packit b00eeb
			g_warning ("prompt object class has no property named '%s'", name);
Packit b00eeb
			break;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		if ((spec->flags & G_PARAM_CONSTRUCT_ONLY) && !(spec->flags & G_PARAM_READABLE)) {
Packit b00eeb
			g_warning ("prompt property '%s' can't be set after construction", name);
Packit b00eeb
			break;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		G_VALUE_COLLECT_INIT (&value, spec->value_type, var_args, 0, &error);
Packit b00eeb
		if (error != NULL) {
Packit b00eeb
			g_warning ("%s", error);
Packit b00eeb
			g_free (error);
Packit b00eeb
			g_value_unset (&value);
Packit b00eeb
			break;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		parameter = g_new0 (GParameter, 1);
Packit b00eeb
		parameter->name = g_intern_string (name);
Packit b00eeb
		memcpy (&parameter->value, &value, sizeof (value));
Packit b00eeb
		result = g_list_prepend (result, parameter);
Packit b00eeb
Packit b00eeb
		name = va_arg (var_args, gchar *);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return result;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_is_prompting:
Packit b00eeb
 *
Packit b00eeb
 * Check if the mock prompter is showing any prompts.
Packit b00eeb
 *
Packit b00eeb
 * Returns: whether prompting
Packit b00eeb
 */
Packit b00eeb
gboolean
Packit b00eeb
gcr_mock_prompter_is_prompting (void)
Packit b00eeb
{
Packit b00eeb
	return g_atomic_int_get (&prompts_a_prompting) > 0;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_get_delay_msec:
Packit b00eeb
 *
Packit b00eeb
 * Get the delay in milliseconds before the mock prompter completes
Packit b00eeb
 * an expected prompt.
Packit b00eeb
 *
Packit b00eeb
 * Returns: the delay
Packit b00eeb
 */
Packit b00eeb
guint
Packit b00eeb
gcr_mock_prompter_get_delay_msec (void)
Packit b00eeb
{
Packit b00eeb
	guint delay_msec;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
	delay_msec = running->delay_msec;
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
Packit b00eeb
	return delay_msec;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_set_delay_msec:
Packit b00eeb
 * @delay_msec: prompt response delay in milliseconds
Packit b00eeb
 *
Packit b00eeb
 * Set the delay in milliseconds before the mock prompter completes
Packit b00eeb
 * an expected prompt.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_set_delay_msec (guint delay_msec)
Packit b00eeb
{
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
	running->delay_msec = delay_msec;
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_expect_confirm_ok:
Packit b00eeb
 * @first_property_name: the first property name in the argument list or %NULL
Packit b00eeb
 * @...: properties to expect
Packit b00eeb
 *
Packit b00eeb
 * Queue an expected response on the mock prompter.
Packit b00eeb
 *
Packit b00eeb
 * Expects a confirmation prompt, and then confirms that prompt by
Packit b00eeb
 * simulating a click on the ok button.
Packit b00eeb
 *
Packit b00eeb
 * Additional property pairs for the prompt can be added in the argument
Packit b00eeb
 * list, in the same way that you would with g_object_new().
Packit b00eeb
 *
Packit b00eeb
 * If the "choice-chosen" property is specified then that value will be
Packit b00eeb
 * set on the prompt as if the user had changed the value.
Packit b00eeb
 *
Packit b00eeb
 * All other properties will be checked against the prompt, and an error
Packit b00eeb
 * will occur if they do not match the value set on the prompt.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_expect_confirm_ok (const gchar *first_property_name,
Packit b00eeb
                                     ...)
Packit b00eeb
{
Packit b00eeb
	MockResponse *response;
Packit b00eeb
	gpointer klass;
Packit b00eeb
	va_list var_args;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	response = g_new0 (MockResponse, 1);
Packit b00eeb
	response->password = NULL;
Packit b00eeb
	response->proceed = TRUE;
Packit b00eeb
Packit b00eeb
	klass = g_type_class_ref (GCR_TYPE_MOCK_PROMPT);
Packit b00eeb
Packit b00eeb
	va_start (var_args, first_property_name);
Packit b00eeb
	response->properties = build_properties (G_OBJECT_CLASS (klass), first_property_name, var_args);
Packit b00eeb
	va_end (var_args);
Packit b00eeb
Packit b00eeb
	g_type_class_unref (klass);
Packit b00eeb
	g_queue_push_tail (&running->responses, response);
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_expect_confirm_cancel:
Packit b00eeb
 *
Packit b00eeb
 * Queue an expected response on the mock prompter.
Packit b00eeb
 *
Packit b00eeb
 * Expects a confirmation prompt, and then cancels that prompt.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_expect_confirm_cancel (void)
Packit b00eeb
{
Packit b00eeb
	MockResponse *response;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	response = g_new0 (MockResponse, 1);
Packit b00eeb
	response->password = NULL;
Packit b00eeb
	response->proceed = FALSE;
Packit b00eeb
Packit b00eeb
	g_queue_push_tail (&running->responses, response);
Packit b00eeb
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_expect_password_ok:
Packit b00eeb
 * @password: the password to return from the prompt
Packit b00eeb
 * @first_property_name: the first property name in the argument list or %NULL
Packit b00eeb
 * @...: properties to expect
Packit b00eeb
 *
Packit b00eeb
 * Queue an expected response on the mock prompter.
Packit b00eeb
 *
Packit b00eeb
 * Expects a password prompt, and returns @password as if the user had entered
Packit b00eeb
 * it and clicked the ok button.
Packit b00eeb
 *
Packit b00eeb
 * Additional property pairs for the prompt can be added in the argument
Packit b00eeb
 * list, in the same way that you would with g_object_new().
Packit b00eeb
 *
Packit b00eeb
 * If the "choice-chosen" property is specified then that value will be
Packit b00eeb
 * set on the prompt as if the user had changed the value.
Packit b00eeb
 *
Packit b00eeb
 * All other properties will be checked against the prompt, and an error
Packit b00eeb
 * will occur if they do not match the value set on the prompt.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_expect_password_ok (const gchar *password,
Packit b00eeb
                                      const gchar *first_property_name,
Packit b00eeb
                                      ...)
Packit b00eeb
{
Packit b00eeb
	MockResponse *response;
Packit b00eeb
	gpointer klass;
Packit b00eeb
	va_list var_args;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
	g_assert (password != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	response = g_new0 (MockResponse, 1);
Packit b00eeb
	response->password = g_strdup (password);
Packit b00eeb
	response->proceed = TRUE;
Packit b00eeb
Packit b00eeb
	klass = g_type_class_ref (GCR_TYPE_MOCK_PROMPT);
Packit b00eeb
Packit b00eeb
	va_start (var_args, first_property_name);
Packit b00eeb
	response->properties = build_properties (G_OBJECT_CLASS (klass), first_property_name, var_args);
Packit b00eeb
	va_end (var_args);
Packit b00eeb
Packit b00eeb
	g_type_class_unref (klass);
Packit b00eeb
	g_queue_push_tail (&running->responses, response);
Packit b00eeb
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_expect_password_cancel:
Packit b00eeb
 *
Packit b00eeb
 * Queue an expected response on the mock prompter.
Packit b00eeb
 *
Packit b00eeb
 * Expects a password prompt, and then cancels that prompt.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_expect_password_cancel (void)
Packit b00eeb
{
Packit b00eeb
	MockResponse *response;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	response = g_new0 (MockResponse, 1);
Packit b00eeb
	response->password = g_strdup ("");
Packit b00eeb
	response->proceed = FALSE;
Packit b00eeb
Packit b00eeb
	g_queue_push_tail (&running->responses, response);
Packit b00eeb
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_expect_close:
Packit b00eeb
 *
Packit b00eeb
 * Queue an expected response on the mock prompter.
Packit b00eeb
 *
Packit b00eeb
 * Expects any prompt, and closes the prompt when it gets it.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_expect_close (void)
Packit b00eeb
{
Packit b00eeb
	MockResponse *response;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	response = g_new0 (MockResponse, 1);
Packit b00eeb
	response->close = TRUE;
Packit b00eeb
Packit b00eeb
	g_queue_push_tail (&running->responses, response);
Packit b00eeb
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_is_expecting:
Packit b00eeb
 *
Packit b00eeb
 * Check if the mock prompter is expecting a response. This will be %TRUE
Packit b00eeb
 * when one of the <literal>gcr_mock_prompter_expect_xxx()</literal>
Packit b00eeb
 * functions have been used to queue an expected prompt, but that prompt
Packit b00eeb
 * response has not be 'used' yet.
Packit b00eeb
 *
Packit b00eeb
 * Returns: whether expecting a prompt
Packit b00eeb
 */
Packit b00eeb
gboolean
Packit b00eeb
gcr_mock_prompter_is_expecting (void)
Packit b00eeb
{
Packit b00eeb
	gboolean expecting;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	expecting = !g_queue_is_empty (&running->responses);
Packit b00eeb
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
Packit b00eeb
	return expecting;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
on_idle_signal_cond (gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GCond *cond = user_data;
Packit b00eeb
	g_cond_signal (cond);
Packit b00eeb
	return FALSE; /* Don't run again */
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/*
Packit b00eeb
 * These next few functions test the new-prompt signals of
Packit b00eeb
 * GcrSystemPrompter. They should probably be in tests, but
Packit b00eeb
 * don't fit there nicely.
Packit b00eeb
 */
Packit b00eeb
static GcrPrompt *
Packit b00eeb
on_new_prompt_skipped (GcrSystemPrompter *prompter,
Packit b00eeb
                       gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (prompter), NULL);
Packit b00eeb
	return NULL;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GcrPrompt *
Packit b00eeb
on_new_prompt_creates (GcrSystemPrompter *prompter,
Packit b00eeb
                       gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (prompter), NULL);
Packit b00eeb
	return g_object_new (GCR_TYPE_MOCK_PROMPT, NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GcrPrompt *
Packit b00eeb
on_new_prompt_not_called (GcrSystemPrompter *prompter,
Packit b00eeb
                          gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (prompter), NULL);
Packit b00eeb
	g_return_val_if_reached (NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gpointer
Packit b00eeb
mock_prompter_thread (gpointer data)
Packit b00eeb
{
Packit b00eeb
	ThreadData *thread_data = data;
Packit b00eeb
	GDBusConnection *connection = NULL;
Packit b00eeb
	GMainContext *context;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GSource *idle;
Packit b00eeb
	gchar *address;
Packit b00eeb
Packit b00eeb
	g_mutex_lock (thread_data->mutex);
Packit b00eeb
	context = g_main_context_new ();
Packit b00eeb
	g_main_context_push_thread_default (context);
Packit b00eeb
Packit b00eeb
	/*
Packit b00eeb
	 * Random choice between signals, and prompt-gtype style of creating
Packit b00eeb
	 * GcrPrompt objects.
Packit b00eeb
	 */
Packit b00eeb
Packit b00eeb
	if (g_random_boolean ()) {
Packit b00eeb
		/* Allows GcrSystemPrompter to create the prompts directly */
Packit b00eeb
		thread_data->prompter = gcr_system_prompter_new (GCR_SYSTEM_PROMPTER_SINGLE,
Packit b00eeb
		                                                 GCR_TYPE_MOCK_PROMPT);
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		/* Create the prompt objects in signal handler */
Packit b00eeb
		thread_data->prompter = gcr_system_prompter_new (GCR_SYSTEM_PROMPTER_SINGLE, 0);
Packit b00eeb
		g_signal_connect (thread_data->prompter, "new-prompt", G_CALLBACK (on_new_prompt_skipped), NULL);
Packit b00eeb
		g_signal_connect (thread_data->prompter, "new-prompt", G_CALLBACK (on_new_prompt_creates), NULL);
Packit b00eeb
		g_signal_connect (thread_data->prompter, "new-prompt", G_CALLBACK (on_new_prompt_not_called), NULL);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, &error);
Packit b00eeb
	if (error == NULL) {
Packit b00eeb
		connection = g_dbus_connection_new_for_address_sync (address,
Packit b00eeb
		                                                     G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
Packit b00eeb
		                                                     G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
Packit b00eeb
		                                                     NULL, NULL, &error);
Packit b00eeb
		if (error == NULL) {
Packit b00eeb
			thread_data->connection = connection;
Packit b00eeb
			gcr_system_prompter_register (GCR_SYSTEM_PROMPTER (thread_data->prompter),
Packit b00eeb
			                              connection);
Packit b00eeb
		} else {
Packit b00eeb
			g_critical ("couldn't create connection: %s", error->message);
Packit b00eeb
			g_error_free (error);
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		g_free (address);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_critical ("mock prompter couldn't get session bus address: %s",
Packit b00eeb
		            egg_error_message (error));
Packit b00eeb
		g_clear_error (&error);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	thread_data->loop = g_main_loop_new (context, FALSE);
Packit b00eeb
	g_mutex_unlock (thread_data->mutex);
Packit b00eeb
Packit b00eeb
	idle = g_idle_source_new ();
Packit b00eeb
	g_source_set_callback (idle, on_idle_signal_cond, thread_data->start_cond, NULL);
Packit b00eeb
	g_source_attach (idle, context);
Packit b00eeb
	g_source_unref (idle);
Packit b00eeb
Packit b00eeb
	g_main_loop_run (thread_data->loop);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (thread_data->mutex);
Packit b00eeb
	g_main_context_pop_thread_default (context);
Packit b00eeb
Packit b00eeb
	gcr_system_prompter_unregister (thread_data->prompter, TRUE);
Packit b00eeb
	g_object_unref (thread_data->prompter);
Packit b00eeb
	thread_data->prompter = NULL;
Packit b00eeb
Packit b00eeb
	if (connection) {
Packit b00eeb
		thread_data->connection = NULL;
Packit b00eeb
Packit b00eeb
		if (!g_dbus_connection_is_closed (connection)) {
Packit b00eeb
			if (!g_dbus_connection_flush_sync (connection, NULL, &error)) {
Packit b00eeb
				g_critical ("connection flush failed: %s", error->message);
Packit b00eeb
				g_error_free (error);
Packit b00eeb
			}
Packit b00eeb
			if (!g_dbus_connection_close_sync (connection, NULL, &error)) {
Packit b00eeb
				g_critical ("connection close failed: %s", error->message);
Packit b00eeb
				g_error_free (error);
Packit b00eeb
			}
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		g_object_unref (connection);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	while (g_main_context_iteration (context, FALSE));
Packit b00eeb
Packit b00eeb
	g_main_context_unref (context);
Packit b00eeb
	g_main_loop_unref (thread_data->loop);
Packit b00eeb
	thread_data->loop = NULL;
Packit b00eeb
Packit b00eeb
	g_mutex_unlock (thread_data->mutex);
Packit b00eeb
	return thread_data;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_start:
Packit b00eeb
 *
Packit b00eeb
 * Start the mock prompter. This is often used from the
Packit b00eeb
 * <literal>setup()</literal> function of tests.
Packit b00eeb
 *
Packit b00eeb
 * Starts the mock prompter in an additional thread. Use the returned DBus bus
Packit b00eeb
 * name with gcr_system_prompt_open_for_prompter() to connect to this prompter.
Packit b00eeb
 *
Packit b00eeb
 * Returns: the bus name that the mock prompter is listening on
Packit b00eeb
 */
Packit b00eeb
const gchar *
Packit b00eeb
gcr_mock_prompter_start (void)
Packit b00eeb
{
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	g_assert (running == NULL);
Packit b00eeb
Packit b00eeb
	running = g_new0 (ThreadData, 1);
Packit b00eeb
	running->mutex = g_new0 (GMutex, 1);
Packit b00eeb
	g_mutex_init (running->mutex);
Packit b00eeb
	running->start_cond = g_new0 (GCond, 1);
Packit b00eeb
	g_cond_init (running->start_cond);
Packit b00eeb
	g_queue_init (&running->responses);
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
Packit b00eeb
	running->thread = g_thread_new ("mock-prompter", mock_prompter_thread, running);
Packit b00eeb
	if (error != NULL)
Packit b00eeb
		g_error ("mock prompter couldn't start thread: %s", error->message);
Packit b00eeb
Packit b00eeb
	g_cond_wait (running->start_cond, running->mutex);
Packit b00eeb
	g_assert (running->loop);
Packit b00eeb
	g_assert (running->prompter);
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
Packit b00eeb
	return g_dbus_connection_get_unique_name (running->connection);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_disconnect:
Packit b00eeb
 *
Packit b00eeb
 * Disconnect the mock prompter
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_disconnect (void)
Packit b00eeb
{
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
	g_assert (running->connection);
Packit b00eeb
Packit b00eeb
	g_dbus_connection_close_sync (running->connection, NULL, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_critical ("disconnect connection close failed: %s", error->message);
Packit b00eeb
		g_error_free (error);
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_mock_prompter_stop:
Packit b00eeb
 *
Packit b00eeb
 * Stop the mock prompter. This is often used from the
Packit b00eeb
 * <literal>teardown()</literal> function of tests.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_mock_prompter_stop (void)
Packit b00eeb
{
Packit b00eeb
	ThreadData *check;
Packit b00eeb
Packit b00eeb
	g_assert (running != NULL);
Packit b00eeb
Packit b00eeb
	g_mutex_lock (running->mutex);
Packit b00eeb
	g_assert (running->loop != NULL);
Packit b00eeb
	g_main_loop_quit (running->loop);
Packit b00eeb
	g_mutex_unlock (running->mutex);
Packit b00eeb
Packit b00eeb
	check = g_thread_join (running->thread);
Packit b00eeb
	g_assert (check == running);
Packit b00eeb
Packit b00eeb
	g_queue_foreach (&running->responses, (GFunc)mock_response_free, NULL);
Packit b00eeb
	g_queue_clear (&running->responses);
Packit b00eeb
Packit b00eeb
	g_cond_clear (running->start_cond);
Packit b00eeb
	g_free (running->start_cond);
Packit b00eeb
	g_mutex_clear (running->mutex);
Packit b00eeb
	g_free (running->mutex);
Packit b00eeb
Packit b00eeb
	g_free (running);
Packit b00eeb
	running = NULL;
Packit b00eeb
}