/* Simple utility code used by the regression tests.
*
* Copyright © 2008-2010 Collabora Ltd.
* Copyright © 2008 Nokia Corporation
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved.
*/
#include "config.h"
#include "util.h"
#include
#ifdef G_OS_UNIX
# include /* for alarm() */
#endif
void
tp_tests_proxy_run_until_prepared (gpointer proxy,
const GQuark *features)
{
GError *error = NULL;
tp_tests_proxy_run_until_prepared_or_failed (proxy, features, &error);
g_assert_no_error (error);
}
/* A GAsyncReadyCallback whose user_data is a GAsyncResult **. It writes a
* reference to the result into that pointer. */
void
tp_tests_result_ready_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GAsyncResult **result = user_data;
*result = g_object_ref (res);
}
/* Run until *result contains a result. Intended to be used with a pending
* async call that uses tp_tests_result_ready_cb. */
void
tp_tests_run_until_result (GAsyncResult **result)
{
/* not synchronous */
g_assert (*result == NULL);
while (*result == NULL)
g_main_context_iteration (NULL, TRUE);
}
gboolean
tp_tests_proxy_run_until_prepared_or_failed (gpointer proxy,
const GQuark *features,
GError **error)
{
GAsyncResult *result = NULL;
gboolean r;
tp_proxy_prepare_async (proxy, features, tp_tests_result_ready_cb, &result);
tp_tests_run_until_result (&result);
r = tp_proxy_prepare_finish (proxy, result, error);
g_object_unref (result);
return r;
}
TpDBusDaemon *
tp_tests_dbus_daemon_dup_or_die (void)
{
TpDBusDaemon *d = tp_dbus_daemon_dup (NULL);
/* In a shared library, this would be very bad (see fd.o #18832), but in a
* regression test that's going to be run under a temporary session bus,
* it's just what we want. */
if (d == NULL)
{
g_error ("Unable to connect to session bus");
}
return d;
}
static void
introspect_cb (TpProxy *proxy G_GNUC_UNUSED,
const gchar *xml G_GNUC_UNUSED,
const GError *error G_GNUC_UNUSED,
gpointer user_data,
GObject *weak_object G_GNUC_UNUSED)
{
g_main_loop_quit (user_data);
}
void
tp_tests_proxy_run_until_dbus_queue_processed (gpointer proxy)
{
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
tp_cli_dbus_introspectable_call_introspect (proxy, -1, introspect_cb,
loop, NULL, NULL);
g_main_loop_run (loop);
g_main_loop_unref (loop);
}
typedef struct {
GMainLoop *loop;
TpHandle handle;
} HandleRequestResult;
static void
handles_requested_cb (TpConnection *connection G_GNUC_UNUSED,
TpHandleType handle_type G_GNUC_UNUSED,
guint n_handles,
const TpHandle *handles,
const gchar * const *ids G_GNUC_UNUSED,
const GError *error,
gpointer user_data,
GObject *weak_object G_GNUC_UNUSED)
{
HandleRequestResult *result = user_data;
g_assert_no_error ((GError *) error);
g_assert_cmpuint (n_handles, ==, 1);
result->handle = handles[0];
}
static void
handle_request_result_finish (gpointer r)
{
HandleRequestResult *result = r;
g_main_loop_quit (result->loop);
}
TpHandle
tp_tests_connection_run_request_contact_handle (TpConnection *connection,
const gchar *id)
{
HandleRequestResult result = { g_main_loop_new (NULL, FALSE), 0 };
const gchar * const ids[] = { id, NULL };
tp_connection_request_handles (connection, -1, TP_HANDLE_TYPE_CONTACT, ids,
handles_requested_cb, &result, handle_request_result_finish, NULL);
g_main_loop_run (result.loop);
g_main_loop_unref (result.loop);
return result.handle;
}
void
_test_assert_empty_strv (const char *file,
int line,
gconstpointer strv)
{
const gchar * const *strings = strv;
if (strv != NULL && strings[0] != NULL)
{
guint i;
g_message ("%s:%d: expected empty strv, but got:", file, line);
for (i = 0; strings[i] != NULL; i++)
{
g_message ("* \"%s\"", strings[i]);
}
g_error ("%s:%d: strv wasn't empty (see above for contents",
file, line);
}
}
void
_tp_tests_assert_strv_equals (const char *file,
int line,
const char *expected_desc,
gconstpointer expected_strv,
const char *actual_desc,
gconstpointer actual_strv)
{
const gchar * const *expected = expected_strv;
const gchar * const *actual = actual_strv;
guint i;
g_assert (expected != NULL);
g_assert (actual != NULL);
for (i = 0; expected[i] != NULL || actual[i] != NULL; i++)
{
if (expected[i] == NULL)
{
g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: "
"NULL == %s", file, line, expected_desc, i,
actual_desc, i, actual[i]);
}
else if (actual[i] == NULL)
{
g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: "
"%s == NULL", file, line, expected_desc, i,
actual_desc, i, expected[i]);
}
else if (tp_strdiff (expected[i], actual[i]))
{
g_error ("%s:%d: assertion failed: (%s)[%u] == (%s)[%u]: "
"%s == %s", file, line, expected_desc, i,
actual_desc, i, expected[i], actual[i]);
}
}
}
void
tp_tests_copy_dir (const gchar *from_dir, const gchar *to_dir)
{
gchar *command;
// If destination directory exist erase it
command = g_strdup_printf ("rm -rf %s", to_dir);
g_assert (system (command) == 0);
g_free (command);
command = g_strdup_printf ("cp -r %s %s", from_dir, to_dir);
g_assert (system (command) == 0);
g_free (command);
// In distcheck mode the files and directory are read-only, fix that
command = g_strdup_printf ("chmod -R +w %s", to_dir);
g_assert (system (command) == 0);
g_free (command);
}
void
tp_tests_create_and_connect_conn (GType conn_type,
const gchar *account,
TpBaseConnection **service_conn,
TpConnection **client_conn)
{
TpDBusDaemon *dbus;
gchar *name;
gchar *conn_path;
GError *error = NULL;
GQuark conn_features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
g_assert (service_conn != NULL);
g_assert (client_conn != NULL);
dbus = tp_tests_dbus_daemon_dup_or_die ();
*service_conn = tp_tests_object_new_static_class (
conn_type,
"account", account,
"protocol", "simple",
NULL);
g_assert (*service_conn != NULL);
g_assert (tp_base_connection_register (*service_conn, "simple",
&name, &conn_path, &error));
g_assert_no_error (error);
*client_conn = tp_connection_new (dbus, name, conn_path,
&error);
g_assert (*client_conn != NULL);
g_assert_no_error (error);
tp_cli_connection_call_connect (*client_conn, -1, NULL, NULL, NULL, NULL);
tp_tests_proxy_run_until_prepared (*client_conn, conn_features);
g_free (name);
g_free (conn_path);
g_object_unref (dbus);
}
/* This object exists solely so that tests/tests.supp can ignore "leaked"
* classes. */
gpointer
tp_tests_object_new_static_class (GType type,
...)
{
va_list ap;
GObject *object;
const gchar *first_property;
va_start (ap, type);
first_property = va_arg (ap, const gchar *);
object = g_object_new_valist (type, first_property, ap);
va_end (ap);
return object;
}
static gboolean
time_out (gpointer nil G_GNUC_UNUSED)
{
g_error ("Timed out");
g_assert_not_reached ();
return FALSE;
}
void
tp_tests_abort_after (guint sec)
{
if (g_getenv ("TP_TESTS_NO_TIMEOUT") != NULL)
return;
g_timeout_add_seconds (sec, time_out, NULL);
#ifdef G_OS_UNIX
/* On Unix, we can kill the process more reliably; this is a safety-catch
* in case it deadlocks or something, in which case the main loop won't be
* processed. The default handler for SIGALRM is process termination. */
alarm (sec + 2);
#endif
}