diff options
Diffstat (limited to 'gio')
-rw-r--r-- | gio/gdbusprivate.c | 6 | ||||
-rw-r--r-- | gio/gnetworkaddress.c | 147 | ||||
-rw-r--r-- | gio/gpollableoutputstream.h | 2 | ||||
-rw-r--r-- | gio/gresource.c | 8 | ||||
-rw-r--r-- | gio/gsocket.c | 16 | ||||
-rw-r--r-- | gio/gsocketclient.c | 2 | ||||
-rw-r--r-- | gio/gsocketlistener.c | 32 | ||||
-rw-r--r-- | gio/gtask.c | 17 | ||||
-rw-r--r-- | gio/gwin32volumemonitor.c | 10 | ||||
-rw-r--r-- | gio/tests/autoptr.c | 2 | ||||
-rw-r--r-- | gio/tests/gsettings.c | 287 | ||||
-rw-r--r-- | gio/tests/gsubprocess.c | 46 | ||||
-rw-r--r-- | gio/tests/meson.build | 20 | ||||
-rw-r--r-- | gio/tests/network-address.c | 103 | ||||
-rw-r--r-- | gio/tests/task.c | 148 | ||||
-rw-r--r-- | gio/win32/gwinhttpvfs.c | 2 |
16 files changed, 591 insertions, 257 deletions
diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index c2a04ae12..1e8e1d64b 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -809,11 +809,11 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, out: g_mutex_unlock (&worker->read_lock); - /* gives up the reference acquired when calling g_input_stream_read_async() */ - _g_dbus_worker_unref (worker); - /* check if there is any pending close */ schedule_pending_close (worker); + + /* gives up the reference acquired when calling g_input_stream_read_async() */ + _g_dbus_worker_unref (worker); } /* called in private thread shared by all GDBusConnection instances (with read-lock held) */ diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c index 60736874e..24af25c2c 100644 --- a/gio/gnetworkaddress.c +++ b/gio/gnetworkaddress.c @@ -38,6 +38,10 @@ #include <string.h> +/* As recommended by RFC 8305 this is the time it waits for a following + DNS response to come in (ipv4 waiting on ipv6 generally) + */ +#define HAPPY_EYEBALLS_RESOLUTION_DELAY_MS 50 /** * SECTION:gnetworkaddress @@ -879,6 +883,12 @@ g_network_address_get_scheme (GNetworkAddress *addr) #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ()) #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator)) +typedef enum { + RESOLVE_STATE_NONE = 0, + RESOLVE_STATE_WAITING_ON_IPV4 = 1 << 0, + RESOLVE_STATE_WAITING_ON_IPV6 = 1 << 1, +} ResolveState; + typedef struct { GSocketAddressEnumerator parent_instance; @@ -887,9 +897,11 @@ typedef struct { GList *last_tail; /* (unowned) (nullable) */ GList *current_item; /* (unowned) (nullable) */ GTask *queued_task; /* (owned) (nullable) */ + GTask *waiting_task; /* (owned) (nullable) */ GError *last_error; /* (owned) (nullable) */ GSource *wait_source; /* (owned) (nullable) */ GMainContext *context; /* (owned) (nullable) */ + ResolveState state; } GNetworkAddressAddressEnumerator; typedef struct { @@ -912,6 +924,7 @@ g_network_address_address_enumerator_finalize (GObject *object) g_clear_pointer (&addr_enum->wait_source, g_source_unref); } g_clear_object (&addr_enum->queued_task); + g_clear_object (&addr_enum->waiting_task); g_clear_error (&addr_enum->last_error); g_object_unref (addr_enum->addr); g_clear_pointer (&addr_enum->addresses, g_list_free); @@ -1093,20 +1106,54 @@ g_network_address_address_enumerator_next (GSocketAddressEnumerator *enumerator return g_object_ref (sockaddr); } +/* + * Each enumeration lazily initializes the internal address list from the + * master list. It does this since addresses come in asynchronously and + * they need to be resorted into the list already in use. + */ +static GSocketAddress * +init_and_query_next_address (GNetworkAddressAddressEnumerator *addr_enum) +{ + GNetworkAddress *addr = addr_enum->addr; + GSocketAddress *sockaddr; + + if (addr_enum->addresses == NULL) + { + addr_enum->current_item = addr_enum->addresses = list_copy_interleaved (addr->priv->sockaddrs); + addr_enum->last_tail = g_list_last (addr_enum->addr->priv->sockaddrs); + if (addr_enum->current_item) + sockaddr = g_object_ref (addr_enum->current_item->data); + else + sockaddr = NULL; + } + else + { + GList *parent_tail = g_list_last (addr_enum->addr->priv->sockaddrs); + + if (addr_enum->last_tail != parent_tail) + { + addr_enum->current_item = list_concat_interleaved (addr_enum->current_item, g_list_next (addr_enum->last_tail)); + addr_enum->last_tail = parent_tail; + } + + if (addr_enum->current_item->next) + { + addr_enum->current_item = g_list_next (addr_enum->current_item); + sockaddr = g_object_ref (addr_enum->current_item->data); + } + else + sockaddr = NULL; + } + + return sockaddr; +} + static void complete_queued_task (GNetworkAddressAddressEnumerator *addr_enum, GTask *task, GError *error) { - GSocketAddress *sockaddr; - - addr_enum->current_item = addr_enum->addresses = list_copy_interleaved (addr_enum->addr->priv->sockaddrs); - addr_enum->last_tail = g_list_last (addr_enum->addr->priv->sockaddrs); - - if (addr_enum->current_item) - sockaddr = g_object_ref (addr_enum->current_item->data); - else - sockaddr = NULL; + GSocketAddress *sockaddr = init_and_query_next_address (addr_enum); if (error) g_task_return_error (task, error); @@ -1123,10 +1170,12 @@ on_address_timeout (gpointer user_data) /* Upon completion it may get unref'd by the owner */ g_object_ref (addr_enum); - /* If ipv6 didn't come in yet, just complete the task */ if (addr_enum->queued_task != NULL) - complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), - g_steal_pointer (&addr_enum->last_error)); + complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), + g_steal_pointer (&addr_enum->last_error)); + else if (addr_enum->waiting_task != NULL) + complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), + NULL); g_clear_pointer (&addr_enum->wait_source, g_source_unref); g_object_unref (addr_enum); @@ -1144,6 +1193,8 @@ got_ipv6_addresses (GObject *source_object, GList *addresses; GError *error = NULL; + addr_enum->state ^= RESOLVE_STATE_WAITING_ON_IPV6; + addresses = g_resolver_lookup_by_name_with_flags_finish (resolver, result, &error); if (!error) { @@ -1163,30 +1214,39 @@ got_ipv6_addresses (GObject *source_object, g_clear_pointer (&addr_enum->wait_source, g_source_unref); } - /* If we got an error before ipv4 then let it handle it. + /* If we got an error before ipv4 then let its response handle it. * If we get ipv6 response first or error second then * immediately complete the task. */ - if (error != NULL && !addr_enum->last_error) + if (error != NULL && !addr_enum->last_error && (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4)) { addr_enum->last_error = g_steal_pointer (&error); - /* This shouldn't happen often but avoid never responding. */ - addr_enum->wait_source = g_timeout_source_new_seconds (1); + addr_enum->wait_source = g_timeout_source_new (HAPPY_EYEBALLS_RESOLUTION_DELAY_MS); g_source_set_callback (addr_enum->wait_source, on_address_timeout, addr_enum, NULL); g_source_attach (addr_enum->wait_source, addr_enum->context); } + else if (addr_enum->waiting_task != NULL) + { + complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), NULL); + } else if (addr_enum->queued_task != NULL) { + GError *task_error = NULL; + + /* If both errored just use the ipv6 one, + but if ipv6 errored and ipv4 didn't we don't error */ + if (error != NULL && addr_enum->last_error) + task_error = g_steal_pointer (&error); + g_clear_error (&addr_enum->last_error); complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), - g_steal_pointer (&error)); + g_steal_pointer (&task_error)); } - else if (error != NULL) - g_clear_error (&error); + g_clear_error (&error); g_object_unref (addr_enum); } @@ -1200,6 +1260,8 @@ got_ipv4_addresses (GObject *source_object, GList *addresses; GError *error = NULL; + addr_enum->state ^= RESOLVE_STATE_WAITING_ON_IPV4; + addresses = g_resolver_lookup_by_name_with_flags_finish (resolver, result, &error); if (!error) { @@ -1216,8 +1278,9 @@ got_ipv4_addresses (GObject *source_object, } /* If ipv6 already came in and errored then we return. - * If ipv6 returned successfully then we don't need to do anything. - * Otherwise we should wait a short while for ipv6 as RFC 8305 suggests. + * If ipv6 returned successfully then we don't need to do anything unless + * another enumeration was waiting on us. + * If ipv6 hasn't come we should wait a short while for it as RFC 8305 suggests. */ if (addr_enum->last_error) { @@ -1226,18 +1289,21 @@ got_ipv4_addresses (GObject *source_object, complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), g_steal_pointer (&error)); } + else if (addr_enum->waiting_task != NULL) + { + complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), NULL); + } else if (addr_enum->queued_task != NULL) { addr_enum->last_error = g_steal_pointer (&error); - addr_enum->wait_source = g_timeout_source_new (50); + addr_enum->wait_source = g_timeout_source_new (HAPPY_EYEBALLS_RESOLUTION_DELAY_MS); g_source_set_callback (addr_enum->wait_source, on_address_timeout, addr_enum, NULL); g_source_attach (addr_enum->wait_source, addr_enum->context); } - else if (error != NULL) - g_clear_error (&error); + g_clear_error (&error); g_object_unref (addr_enum); } @@ -1251,12 +1317,11 @@ g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enum G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator); GSocketAddress *sockaddr; GTask *task; - GNetworkAddress *addr = addr_enum->addr; task = g_task_new (addr_enum, cancellable, callback, user_data); g_task_set_source_tag (task, g_network_address_address_enumerator_next_async); - if (addr_enum->addresses == NULL) + if (addr_enum->addresses == NULL && addr_enum->state == RESOLVE_STATE_NONE) { GNetworkAddress *addr = addr_enum->addr; GResolver *resolver = g_resolver_get_default (); @@ -1280,6 +1345,7 @@ g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enum * times before the initial callback has been called */ g_assert (addr_enum->queued_task == NULL); + addr_enum->state = RESOLVE_STATE_WAITING_ON_IPV4 | RESOLVE_STATE_WAITING_ON_IPV6; addr_enum->queued_task = g_steal_pointer (&task); /* Lookup in parallel as per RFC 8305 */ g_resolver_lookup_by_name_with_flags_async (resolver, @@ -1300,34 +1366,17 @@ g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enum g_object_unref (resolver); } - if (addr_enum->addresses == NULL) + sockaddr = init_and_query_next_address (addr_enum); + if (sockaddr == NULL && (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4 || + addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV6)) { - g_assert (addr->priv->sockaddrs); - - addr_enum->current_item = addr_enum->addresses = list_copy_interleaved (addr->priv->sockaddrs); - sockaddr = g_object_ref (addr_enum->current_item->data); + addr_enum->waiting_task = task; } else { - GList *parent_tail = g_list_last (addr_enum->addr->priv->sockaddrs); - - if (addr_enum->last_tail != parent_tail) - { - addr_enum->current_item = list_concat_interleaved (addr_enum->current_item, g_list_next (addr_enum->last_tail)); - addr_enum->last_tail = parent_tail; - } - - if (addr_enum->current_item->next) - { - addr_enum->current_item = g_list_next (addr_enum->current_item); - sockaddr = g_object_ref (addr_enum->current_item->data); - } - else - sockaddr = NULL; + g_task_return_pointer (task, sockaddr, g_object_unref); + g_object_unref (task); } - - g_task_return_pointer (task, sockaddr, g_object_unref); - g_object_unref (task); } static GSocketAddress * diff --git a/gio/gpollableoutputstream.h b/gio/gpollableoutputstream.h index 1ef830b57..c1e7ad889 100644 --- a/gio/gpollableoutputstream.h +++ b/gio/gpollableoutputstream.h @@ -35,7 +35,7 @@ G_BEGIN_DECLS /** * GPollableOutputStream: * - * An interface for a #GOutputStream that can be polled for readability. + * An interface for a #GOutputStream that can be polled for writeability. * * Since: 2.28 */ diff --git a/gio/gresource.c b/gio/gresource.c index e71db43ed..9aaae8b53 100644 --- a/gio/gresource.c +++ b/gio/gresource.c @@ -151,7 +151,7 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref) * When debugging a program or testing a change to an installed version, it is often useful to be able to * replace resources in the program or library, without recompiling, for debugging or quick hacking and testing * purposes. Since GLib 2.50, it is possible to use the `G_RESOURCE_OVERLAYS` environment variable to selectively overlay - * resources with replacements from the filesystem. It is a colon-separated list of substitutions to perform + * resources with replacements from the filesystem. It is a %G_SEARCHPATH_SEPARATOR-separated list of substitutions to perform * during resource lookups. * * A substitution has the form @@ -332,7 +332,7 @@ g_resource_find_overlay (const gchar *path, gchar **parts; gint i, j; - parts = g_strsplit (envvar, ":", 0); + parts = g_strsplit (envvar, G_SEARCHPATH_SEPARATOR_S, 0); /* Sanity check the parts, dropping those that are invalid. * 'i' may grow faster than 'j'. @@ -378,9 +378,9 @@ g_resource_find_overlay (const gchar *path, continue; } - if (eq[1] != '/') + if (!g_path_is_absolute (eq + 1)) { - g_critical ("G_RESOURCE_OVERLAYS segment '%s' lacks leading '/' after '='. Ignoring", part); + g_critical ("G_RESOURCE_OVERLAYS segment '%s' does not have an absolute path after '='. Ignoring", part); g_free (part); continue; } diff --git a/gio/gsocket.c b/gio/gsocket.c index b1db8e645..92baa62ea 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -4609,7 +4609,13 @@ g_socket_send_message (GSocket *socket, cancellable, error); if (res == G_POLLABLE_RETURN_WOULD_BLOCK) - socket_set_error_lazy (error, EWOULDBLOCK, _("Error sending message: %s")); + { +#ifndef G_OS_WIN32 + socket_set_error_lazy (error, EWOULDBLOCK, _("Error sending message: %s")); +#else + socket_set_error_lazy (error, WSAEWOULDBLOCK, _("Error sending message: %s")); +#endif + } return res == G_POLLABLE_RETURN_OK ? bytes_written : -1; } @@ -5056,7 +5062,13 @@ g_socket_send_messages_with_timeout (GSocket *socket, cancellable, &msg_error); if (pollable_result == G_POLLABLE_RETURN_WOULD_BLOCK) - socket_set_error_lazy (&msg_error, EWOULDBLOCK, _("Error sending message: %s")); + { +#ifndef G_OS_WIN32 + socket_set_error_lazy (&msg_error, EWOULDBLOCK, _("Error sending message: %s")); +#else + socket_set_error_lazy (&msg_error, WSAEWOULDBLOCK, _("Error sending message: %s")); +#endif + } result = pollable_result == G_POLLABLE_RETURN_OK ? bytes_written : -1; diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c index 29a5e5598..11e92e909 100644 --- a/gio/gsocketclient.c +++ b/gio/gsocketclient.c @@ -1567,7 +1567,7 @@ g_socket_client_connected_callback (GObject *source, GProxy *proxy; const gchar *protocol; - if (g_cancellable_is_cancelled (attempt->cancellable) || task_completed_or_cancelled (data->task)) + if (task_completed_or_cancelled (data->task) || g_cancellable_is_cancelled (attempt->cancellable)) { g_object_unref (data->task); connection_attempt_unref (attempt); diff --git a/gio/gsocketlistener.c b/gio/gsocketlistener.c index ab17678a9..a2c879d9c 100644 --- a/gio/gsocketlistener.c +++ b/gio/gsocketlistener.c @@ -773,6 +773,19 @@ g_socket_listener_accept (GSocketListener *listener, return connection; } +typedef struct +{ + GList *sources; /* (element-type GSource) */ + gboolean returned_yet; +} AcceptSocketAsyncData; + +static void +accept_socket_async_data_free (AcceptSocketAsyncData *data) +{ + free_sources (data->sources); + g_free (data); +} + static gboolean accept_ready (GSocket *accept_socket, GIOCondition condition, @@ -782,6 +795,12 @@ accept_ready (GSocket *accept_socket, GError *error = NULL; GSocket *socket; GObject *source_object; + AcceptSocketAsyncData *data = g_task_get_task_data (task); + + /* Don’t call g_task_return_*() multiple times if we have multiple incoming + * connections in the same #GMainContext iteration. */ + if (data->returned_yet) + return G_SOURCE_REMOVE; socket = g_socket_accept (accept_socket, g_task_get_cancellable (task), &error); if (socket) @@ -798,8 +817,10 @@ accept_ready (GSocket *accept_socket, g_task_return_error (task, error); } + data->returned_yet = TRUE; g_object_unref (task); - return FALSE; + + return G_SOURCE_REMOVE; } /** @@ -824,8 +845,8 @@ g_socket_listener_accept_socket_async (GSocketListener *listener, gpointer user_data) { GTask *task; - GList *sources; GError *error = NULL; + AcceptSocketAsyncData *data = NULL; task = g_task_new (listener, cancellable, callback, user_data); g_task_set_source_tag (task, g_socket_listener_accept_socket_async); @@ -837,12 +858,15 @@ g_socket_listener_accept_socket_async (GSocketListener *listener, return; } - sources = add_sources (listener, + data = g_new0 (AcceptSocketAsyncData, 1); + data->returned_yet = FALSE; + data->sources = add_sources (listener, accept_ready, task, cancellable, g_main_context_get_thread_default ()); - g_task_set_task_data (task, sources, (GDestroyNotify) free_sources); + g_task_set_task_data (task, g_steal_pointer (&data), + (GDestroyNotify) accept_socket_async_data_free); } /** diff --git a/gio/gtask.c b/gio/gtask.c index aa98f752c..346d2ec5b 100644 --- a/gio/gtask.c +++ b/gio/gtask.c @@ -1,6 +1,6 @@ /* GIO - GLib Input, Output and Streaming Library * - * Copyright 2011 Red Hat, Inc. + * Copyright 2011-2018 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1260,9 +1260,18 @@ g_task_return (GTask *task, */ if (g_source_get_time (source) > task->creation_time) { - g_task_return_now (task); - g_object_unref (task); - return; + /* Finally, if the task has been cancelled, we shouldn't + * return synchronously from inside the + * GCancellable::cancelled handler. It's easier to run + * another iteration of the main loop than tracking how the + * cancellation was handled. + */ + if (!g_cancellable_is_cancelled (task->cancellable)) + { + g_task_return_now (task); + g_object_unref (task); + return; + } } } diff --git a/gio/gwin32volumemonitor.c b/gio/gwin32volumemonitor.c index c9db68a8a..512471834 100644 --- a/gio/gwin32volumemonitor.c +++ b/gio/gwin32volumemonitor.c @@ -111,7 +111,7 @@ get_mounts (GVolumeMonitor *volume_monitor) { DWORD drives; gchar drive[4] = "A:\\"; - GList *list = NULL; + GQueue queue = G_QUEUE_INIT; drives = get_viewable_logical_drives (); @@ -121,13 +121,13 @@ get_mounts (GVolumeMonitor *volume_monitor) while (drives && drive[0] <= 'Z') { if (drives & 1) - { - list = g_list_prepend (list, _g_win32_mount_new (volume_monitor, drive, NULL)); - } + g_queue_push_tail (&queue, _g_win32_mount_new (volume_monitor, drive, NULL)); + drives >>= 1; drive[0]++; } - return list; + + return g_steal_pointer (&queue.head); } /* actually 'mounting' volumes is out of GIOs business on win32, so no volumes are delivered either */ diff --git a/gio/tests/autoptr.c b/gio/tests/autoptr.c index 9ff1428ea..55a1c91fb 100644 --- a/gio/tests/autoptr.c +++ b/gio/tests/autoptr.c @@ -8,7 +8,7 @@ test_autoptr (void) g_autofree gchar *path = g_file_get_path (p); g_autofree gchar *istr = g_inet_address_to_string (a); - g_assert_cmpstr (path, ==, "/blah"); + g_assert_cmpstr (path, ==, G_DIR_SEPARATOR_S "blah"); g_assert_cmpstr (istr, ==, "127.0.0.1"); } diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index f254c3195..640f3a31c 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -1,6 +1,8 @@ #include <stdlib.h> #include <locale.h> #include <libintl.h> +#include <unistd.h> +#include <sys/types.h> #include <gio/gio.h> #include <gstdio.h> #define G_SETTINGS_ENABLE_BACKEND @@ -53,10 +55,10 @@ test_basic (void) "delay-apply", &delay_apply, NULL); g_assert_cmpstr (str, ==, "org.gtk.test"); - g_assert (b != NULL); + g_assert_nonnull (b); g_assert_cmpstr (path, ==, "/tests/"); - g_assert (!has_unapplied); - g_assert (!delay_apply); + g_assert_false (has_unapplied); + g_assert_false (delay_apply); g_free (str); g_object_unref (b); g_free (path); @@ -114,7 +116,7 @@ test_unknown_key (void) settings = g_settings_new ("org.gtk.test"); value = g_settings_get_value (settings, "no_such_key"); - g_assert (value == NULL); + g_assert_null (value); g_object_unref (settings); return; @@ -139,7 +141,7 @@ test_no_schema (void) settings = g_settings_new ("no.such.schema"); - g_assert (settings == NULL); + g_assert_null (settings); return; } g_test_trap_subprocess (NULL, 0, 0); @@ -168,7 +170,7 @@ test_wrong_type (void) g_settings_get (settings, "greeting", "o", &str); g_test_assert_expected_messages (); - g_assert (str == NULL); + g_assert_null (str); g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*expects type 's'*"); @@ -358,28 +360,28 @@ test_complex_types (void) g_settings_get (settings, "test-array", "ai", &iter); g_assert_cmpint (g_variant_iter_n_children (iter), ==, 6); - g_assert (g_variant_iter_next (iter, "i", &i1)); + g_assert_true (g_variant_iter_next (iter, "i", &i1)); g_assert_cmpint (i1, ==, 0); - g_assert (g_variant_iter_next (iter, "i", &i1)); + g_assert_true (g_variant_iter_next (iter, "i", &i1)); g_assert_cmpint (i1, ==, 1); - g_assert (g_variant_iter_next (iter, "i", &i1)); + g_assert_true (g_variant_iter_next (iter, "i", &i1)); g_assert_cmpint (i1, ==, 2); - g_assert (g_variant_iter_next (iter, "i", &i1)); + g_assert_true (g_variant_iter_next (iter, "i", &i1)); g_assert_cmpint (i1, ==, 3); - g_assert (g_variant_iter_next (iter, "i", &i1)); + g_assert_true (g_variant_iter_next (iter, "i", &i1)); g_assert_cmpint (i1, ==, 4); - g_assert (g_variant_iter_next (iter, "i", &i1)); + g_assert_true (g_variant_iter_next (iter, "i", &i1)); g_assert_cmpint (i1, ==, 5); - g_assert (!g_variant_iter_next (iter, "i", &i1)); + g_assert_false (g_variant_iter_next (iter, "i", &i1)); g_variant_iter_free (iter); g_settings_get (settings, "test-dict", "a{sau}", &iter); g_assert_cmpint (g_variant_iter_n_children (iter), ==, 2); - g_assert (g_variant_iter_next (iter, "{&s@au}", &s, &v)); + g_assert_true (g_variant_iter_next (iter, "{&s@au}", &s, &v)); g_assert_cmpstr (s, ==, "AC"); g_assert_cmpstr ((char *)g_variant_get_type (v), ==, "au"); g_variant_unref (v); - g_assert (g_variant_iter_next (iter, "{&s@au}", &s, &v)); + g_assert_true (g_variant_iter_next (iter, "{&s@au}", &s, &v)); g_assert_cmpstr (s, ==, "IV"); g_assert_cmpstr ((char *)g_variant_get_type (v), ==, "au"); g_variant_unref (v); @@ -420,14 +422,14 @@ test_changes (void) changed_cb_called = FALSE; g_settings_set (settings, "greeting", "s", "new greeting"); - g_assert (changed_cb_called); + g_assert_true (changed_cb_called); settings2 = g_settings_new ("org.gtk.test"); changed_cb_called = FALSE; g_settings_set (settings2, "greeting", "s", "hi"); - g_assert (changed_cb_called); + g_assert_true (changed_cb_called); g_object_unref (settings2); g_object_unref (settings); @@ -479,11 +481,11 @@ test_delay_apply (void) g_settings_set (settings, "greeting", "s", "greetings from test_delay_apply"); - g_assert (changed_cb_called); - g_assert (!changed_cb_called2); + g_assert_true (changed_cb_called); + g_assert_false (changed_cb_called2); writable = g_settings_is_writable (settings, "greeting"); - g_assert (writable); + g_assert_true (writable); g_settings_get (settings, "greeting", "s", &str); g_assert_cmpstr (str, ==, "greetings from test_delay_apply"); @@ -500,16 +502,16 @@ test_delay_apply (void) g_free (str); str = NULL; - g_assert (g_settings_get_has_unapplied (settings)); - g_assert (!g_settings_get_has_unapplied (settings2)); + g_assert_true (g_settings_get_has_unapplied (settings)); + g_assert_false (g_settings_get_has_unapplied (settings2)); changed_cb_called = FALSE; changed_cb_called2 = FALSE; g_settings_apply (settings); - g_assert (!changed_cb_called); - g_assert (changed_cb_called2); + g_assert_false (changed_cb_called); + g_assert_true (changed_cb_called2); g_settings_get (settings, "greeting", "s", &str); g_assert_cmpstr (str, ==, "greetings from test_delay_apply"); @@ -521,8 +523,8 @@ test_delay_apply (void) g_free (str); str = NULL; - g_assert (!g_settings_get_has_unapplied (settings)); - g_assert (!g_settings_get_has_unapplied (settings2)); + g_assert_false (g_settings_get_has_unapplied (settings)); + g_assert_false (g_settings_get_has_unapplied (settings2)); g_settings_reset (settings, "greeting"); g_settings_apply (settings); @@ -568,11 +570,11 @@ test_delay_revert (void) g_free (str); str = NULL; - g_assert (g_settings_get_has_unapplied (settings)); + g_assert_true (g_settings_get_has_unapplied (settings)); g_settings_revert (settings); - g_assert (!g_settings_get_has_unapplied (settings)); + g_assert_false (g_settings_get_has_unapplied (settings)); g_settings_get (settings, "greeting", "s", &str); g_assert_cmpstr (str, ==, "top o' the morning"); @@ -603,13 +605,13 @@ test_delay_child (void) settings = g_settings_new ("org.gtk.test"); g_settings_delay (settings); g_object_get (settings, "delay-apply", &delay, NULL); - g_assert (delay); + g_assert_true (delay); child = g_settings_get_child (settings, "basic-types"); - g_assert (child != NULL); + g_assert_nonnull (child); g_object_get (child, "delay-apply", &delay, NULL); - g_assert (!delay); + g_assert_false (delay); g_settings_get (child, "test-byte", "y", &byte); g_assert_cmpuint (byte, ==, 36); @@ -634,10 +636,10 @@ keys_changed_cb (GSettings *settings, g_assert_cmpint (n_keys, ==, 2); - g_assert ((keys[0] == g_quark_from_static_string ("greeting") && - keys[1] == g_quark_from_static_string ("farewell")) || - (keys[1] == g_quark_from_static_string ("greeting") && - keys[0] == g_quark_from_static_string ("farewell"))); + g_assert_true ((keys[0] == g_quark_from_static_string ("greeting") && + keys[1] == g_quark_from_static_string ("farewell")) || + (keys[1] == g_quark_from_static_string ("greeting") && + keys[0] == g_quark_from_static_string ("farewell"))); g_settings_get (settings, "greeting", "s", &str); g_assert_cmpstr (str, ==, "greetings from test_atomic"); @@ -1297,7 +1299,7 @@ test_simple_binding (void) g_free (s); g_settings_set_strv (settings, "strv", NULL); g_object_get (obj, "strv", &strv, NULL); - g_assert (strv != NULL); + g_assert_nonnull (strv); g_assert_cmpint (g_strv_length (strv), ==, 0); g_strfreev (strv); @@ -1401,14 +1403,14 @@ test_bind_writable (void) g_settings_bind_writable (settings, "int", obj, "bool", FALSE); g_object_get (obj, "bool", &b, NULL); - g_assert (b); + g_assert_true (b); g_settings_unbind (obj, "bool"); g_settings_bind_writable (settings, "int", obj, "bool", TRUE); g_object_get (obj, "bool", &b, NULL); - g_assert (!b); + g_assert_false (b); g_object_unref (obj); g_object_unref (settings); @@ -1724,7 +1726,7 @@ test_keyfile (void) g_free (str); writable = g_settings_is_writable (settings, "greeting"); - g_assert (writable); + g_assert_true (writable); g_settings_set (settings, "greeting", "s", "see if this works"); str = g_settings_get_string (settings, "greeting"); @@ -1736,7 +1738,7 @@ test_keyfile (void) g_settings_apply (settings); keyfile = g_key_file_new (); - g_assert (g_key_file_load_from_file (keyfile, "keyfile/gsettings.store", 0, NULL)); + g_assert_true (g_key_file_load_from_file (keyfile, "keyfile/gsettings.store", 0, NULL)); str = g_key_file_get_string (keyfile, "tests", "greeting", NULL); g_assert_cmpstr (str, ==, "'see if this works'"); @@ -1750,10 +1752,10 @@ test_keyfile (void) g_settings_reset (settings, "greeting"); g_settings_apply (settings); keyfile = g_key_file_new (); - g_assert (g_key_file_load_from_file (keyfile, "keyfile/gsettings.store", 0, NULL)); + g_assert_true (g_key_file_load_from_file (keyfile, "keyfile/gsettings.store", 0, NULL)); str = g_key_file_get_string (keyfile, "tests", "greeting", NULL); - g_assert (str == NULL); + g_assert_null (str); called = FALSE; g_signal_connect (settings, "changed::greeting", G_CALLBACK (key_changed_cb), &called); @@ -1789,16 +1791,23 @@ test_keyfile (void) g_settings_set (settings, "farewell", "s", "cheerio"); - called = FALSE; - g_signal_connect (settings, "writable-changed::greeting", G_CALLBACK (key_changed_cb), &called); + /* When executing as root, changing the mode of the keyfile will have + * no effect on the writability of the settings. + */ + if (geteuid () != 0) + { + called = FALSE; + g_signal_connect (settings, "writable-changed::greeting", + G_CALLBACK (key_changed_cb), &called); - g_chmod ("keyfile", 0500); - while (!called) - g_main_context_iteration (NULL, FALSE); - g_signal_handlers_disconnect_by_func (settings, key_changed_cb, &called); + g_chmod ("keyfile", 0500); + while (!called) + g_main_context_iteration (NULL, FALSE); + g_signal_handlers_disconnect_by_func (settings, key_changed_cb, &called); - writable = g_settings_is_writable (settings, "greeting"); - g_assert (!writable); + writable = g_settings_is_writable (settings, "greeting"); + g_assert_false (writable); + } g_key_file_free (keyfile); g_free (data); @@ -1827,7 +1836,7 @@ test_child_schema (void) settings = g_settings_new ("org.gtk.test"); child = g_settings_get_child (settings, "basic-types"); - g_assert (child != NULL); + g_assert_nonnull (child); g_settings_get (child, "test-byte", "y", &byte); g_assert_cmpint (byte, ==, 36); @@ -1860,7 +1869,7 @@ test_strinfo (void) builder = g_string_new (NULL); strinfo_builder_append_item (builder, "foo", 1); strinfo_builder_append_item (builder, "bar", 2); - g_assert (strinfo_builder_append_alias (builder, "baz", "bar")); + g_assert_true (strinfo_builder_append_alias (builder, "baz", "bar")); g_assert_cmpmem (builder->str, builder->len, strinfo, length * 4); g_string_free (builder, TRUE); } @@ -1874,22 +1883,22 @@ test_strinfo (void) g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "quux"), ==, NULL); - g_assert (strinfo_enum_from_string (strinfo, length, "foo", &result)); + g_assert_true (strinfo_enum_from_string (strinfo, length, "foo", &result)); g_assert_cmpint (result, ==, 1); - g_assert (strinfo_enum_from_string (strinfo, length, "bar", &result)); + g_assert_true (strinfo_enum_from_string (strinfo, length, "bar", &result)); g_assert_cmpint (result, ==, 2); - g_assert (!strinfo_enum_from_string (strinfo, length, "baz", &result)); - g_assert (!strinfo_enum_from_string (strinfo, length, "quux", &result)); + g_assert_false (strinfo_enum_from_string (strinfo, length, "baz", &result)); + g_assert_false (strinfo_enum_from_string (strinfo, length, "quux", &result)); g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 0), ==, NULL); g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 1), ==, "foo"); g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 2), ==, "bar"); g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 3), ==, NULL); - g_assert (strinfo_is_string_valid (strinfo, length, "foo")); - g_assert (strinfo_is_string_valid (strinfo, length, "bar")); - g_assert (!strinfo_is_string_valid (strinfo, length, "baz")); - g_assert (!strinfo_is_string_valid (strinfo, length, "quux")); + g_assert_true (strinfo_is_string_valid (strinfo, length, "foo")); + g_assert_true (strinfo_is_string_valid (strinfo, length, "bar")); + g_assert_false (strinfo_is_string_valid (strinfo, length, "baz")); + g_assert_false (strinfo_is_string_valid (strinfo, length, "quux")); } static void @@ -2152,13 +2161,13 @@ test_range (void) G_GNUC_BEGIN_IGNORE_DEPRECATIONS value = g_variant_new_int32 (1); - g_assert (!g_settings_range_check (settings, "val", value)); + g_assert_false (g_settings_range_check (settings, "val", value)); g_variant_unref (value); value = g_variant_new_int32 (33); - g_assert (g_settings_range_check (settings, "val", value)); + g_assert_true (g_settings_range_check (settings, "val", value)); g_variant_unref (value); value = g_variant_new_int32 (45); - g_assert (!g_settings_range_check (settings, "val", value)); + g_assert_false (g_settings_range_check (settings, "val", value)); g_variant_unref (value); G_GNUC_END_IGNORE_DEPRECATIONS @@ -2224,8 +2233,8 @@ test_list_items (void) children = g_settings_list_children (settings); keys = g_settings_schema_list_keys (schema); - g_assert (strv_set_equal (children, "basic-types", "complex-types", "localized", NULL)); - g_assert (strv_set_equal (keys, "greeting", "farewell", NULL)); + g_assert_true (strv_set_equal (children, "basic-types", "complex-types", "localized", NULL)); + g_assert_true (strv_set_equal (keys, "greeting", "farewell", NULL)); g_strfreev (children); g_strfreev (keys); @@ -2245,26 +2254,26 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS schemas = g_settings_list_schemas (); G_GNUC_END_IGNORE_DEPRECATIONS - g_assert (strv_set_equal ((gchar **)relocs, - "org.gtk.test.no-path", - "org.gtk.test.extends.base", - "org.gtk.test.extends.extended", - NULL)); - - g_assert (strv_set_equal ((gchar **)schemas, - "org.gtk.test", - "org.gtk.test.basic-types", - "org.gtk.test.complex-types", - "org.gtk.test.localized", - "org.gtk.test.binding", - "org.gtk.test.enums", - "org.gtk.test.enums.direct", - "org.gtk.test.range", - "org.gtk.test.range.direct", - "org.gtk.test.mapped", - "org.gtk.test.descriptions", - "org.gtk.test.per-desktop", - NULL)); + g_assert_true (strv_set_equal ((gchar **)relocs, + "org.gtk.test.no-path", + "org.gtk.test.extends.base", + "org.gtk.test.extends.extended", + NULL)); + + g_assert_true (strv_set_equal ((gchar **)schemas, + "org.gtk.test", + "org.gtk.test.basic-types", + "org.gtk.test.complex-types", + "org.gtk.test.localized", + "org.gtk.test.binding", + "org.gtk.test.enums", + "org.gtk.test.enums.direct", + "org.gtk.test.range", + "org.gtk.test.range.direct", + "org.gtk.test.mapped", + "org.gtk.test.descriptions", + "org.gtk.test.per-desktop", + NULL)); } static gboolean @@ -2294,7 +2303,7 @@ map_func (GVariant *value, } else { - g_assert (value == NULL); + g_assert_null (value); *result = g_variant_new_int32 (5); return TRUE; } @@ -2366,7 +2375,7 @@ test_schema_source (void) /* make sure it fails properly */ parent = g_settings_schema_source_get_default (); source = g_settings_schema_source_new_from_directory ("/path/that/does/not/exist", parent, TRUE, &error); - g_assert (source == NULL); + g_assert_null (source); g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT); g_clear_error (&error); @@ -2385,60 +2394,60 @@ test_schema_source (void) /* create a source with the parent */ source = g_settings_schema_source_new_from_directory ("schema-source", parent, TRUE, &error); g_assert_no_error (error); - g_assert (source != NULL); + g_assert_nonnull (source); /* check recursive lookups are working */ schema = g_settings_schema_source_lookup (source, "org.gtk.test", TRUE); - g_assert (schema != NULL); + g_assert_nonnull (schema); g_settings_schema_unref (schema); /* check recursive lookups for non-existent schemas */ schema = g_settings_schema_source_lookup (source, "org.gtk.doesnotexist", TRUE); - g_assert (schema == NULL); + g_assert_null (schema); /* check non-recursive for schema that only exists in lower layers */ schema = g_settings_schema_source_lookup (source, "org.gtk.test", FALSE); - g_assert (schema == NULL); + g_assert_null (schema); /* check non-recursive lookup for non-existent */ schema = g_settings_schema_source_lookup (source, "org.gtk.doesnotexist", FALSE); - g_assert (schema == NULL); + g_assert_null (schema); /* check non-recursive for schema that exists in toplevel */ schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", FALSE); - g_assert (schema != NULL); + g_assert_nonnull (schema); g_settings_schema_unref (schema); /* check recursive for schema that exists in toplevel */ schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", TRUE); - g_assert (schema != NULL); + g_assert_nonnull (schema); /* try to use it for something */ settings = g_settings_new_full (schema, backend, g_settings_schema_get_path (schema)); g_settings_schema_unref (schema); enabled = FALSE; g_settings_get (settings, "enabled", "b", &enabled); - g_assert (enabled); + g_assert_true (enabled); g_object_unref (settings); g_settings_schema_source_unref (source); /* try again, but with no parent */ source = g_settings_schema_source_new_from_directory ("schema-source", NULL, FALSE, NULL); - g_assert (source != NULL); + g_assert_nonnull (source); /* should not find it this time, even if recursive... */ schema = g_settings_schema_source_lookup (source, "org.gtk.test", FALSE); - g_assert (schema == NULL); + g_assert_null (schema); schema = g_settings_schema_source_lookup (source, "org.gtk.test", TRUE); - g_assert (schema == NULL); + g_assert_null (schema); /* should still find our own... */ schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", TRUE); - g_assert (schema != NULL); + g_assert_nonnull (schema); g_settings_schema_unref (schema); schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", FALSE); - g_assert (schema != NULL); + g_assert_nonnull (schema); g_settings_schema_unref (schema); g_settings_schema_source_unref (source); @@ -2451,14 +2460,14 @@ test_schema_list_keys (void) gchar **keys; GSettingsSchemaSource *src = g_settings_schema_source_get_default (); GSettingsSchema *schema = g_settings_schema_source_lookup (src, "org.gtk.test", TRUE); - g_assert (schema != NULL); + g_assert_nonnull (schema); keys = g_settings_schema_list_keys (schema); - g_assert (strv_set_equal ((gchar **)keys, - "greeting", - "farewell", - NULL)); + g_assert_true (strv_set_equal ((gchar **)keys, + "greeting", + "farewell", + NULL)); g_strfreev (keys); g_settings_schema_unref (schema); @@ -2488,27 +2497,27 @@ test_actions (void) c1 = c2 = c3 = FALSE; g_settings_set_string (settings, "test-string", "hello world"); check_and_free (g_action_get_state (string), "'hello world'"); - g_assert (c1 && c2 && !c3); + g_assert_true (c1 && c2 && !c3); c1 = c2 = c3 = FALSE; g_action_activate (string, g_variant_new_string ("hihi")); check_and_free (g_settings_get_value (settings, "test-string"), "'hihi'"); - g_assert (c1 && c2 && !c3); + g_assert_true (c1 && c2 && !c3); c1 = c2 = c3 = FALSE; g_action_change_state (string, g_variant_new_string ("kthxbye")); check_and_free (g_settings_get_value (settings, "test-string"), "'kthxbye'"); - g_assert (c1 && c2 && !c3); + g_assert_true (c1 && c2 && !c3); c1 = c2 = c3 = FALSE; g_action_change_state (toggle, g_variant_new_boolean (TRUE)); - g_assert (g_settings_get_boolean (settings, "test-boolean")); - g_assert (c1 && !c2 && c3); + g_assert_true (g_settings_get_boolean (settings, "test-boolean")); + g_assert_true (c1 && !c2 && c3); c1 = c2 = c3 = FALSE; g_action_activate (toggle, NULL); - g_assert (!g_settings_get_boolean (settings, "test-boolean")); - g_assert (c1 && !c2 && c3); + g_assert_false (g_settings_get_boolean (settings, "test-boolean")); + g_assert_true (c1 && !c2 && c3); g_object_get (string, "name", &name, @@ -2519,9 +2528,9 @@ test_actions (void) NULL); g_assert_cmpstr (name, ==, "test-string"); - g_assert (g_variant_type_equal (param_type, G_VARIANT_TYPE_STRING)); - g_assert (enabled); - g_assert (g_variant_type_equal (state_type, G_VARIANT_TYPE_STRING)); + g_assert_true (g_variant_type_equal (param_type, G_VARIANT_TYPE_STRING)); + g_assert_true (enabled); + g_assert_true (g_variant_type_equal (state_type, G_VARIANT_TYPE_STRING)); g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "kthxbye"); g_free (name); @@ -2558,7 +2567,7 @@ test_null_backend (void) g_free (str); writable = g_settings_is_writable (settings, "greeting"); - g_assert (!writable); + g_assert_false (writable); g_settings_reset (settings, "greeting"); @@ -2579,7 +2588,7 @@ test_memory_backend (void) GSettingsBackend *backend; backend = g_memory_settings_backend_new (); - g_assert (G_IS_SETTINGS_BACKEND (backend)); + g_assert_true (G_IS_SETTINGS_BACKEND (backend)); g_object_unref (backend); } @@ -2634,7 +2643,7 @@ test_default_value (void) g_settings_schema_unref (schema); g_settings_schema_key_ref (key); - g_assert (g_variant_type_equal (g_settings_schema_key_get_value_type (key), G_VARIANT_TYPE_STRING)); + g_assert_true (g_variant_type_equal (g_settings_schema_key_get_value_type (key), G_VARIANT_TYPE_STRING)); v = g_settings_schema_key_get_default_value (key); str = g_variant_get_string (v, NULL); @@ -2772,7 +2781,7 @@ test_extended_schema (void) settings = g_settings_new_with_path ("org.gtk.test.extends.extended", "/test/extendes/"); g_object_get (settings, "settings-schema", &schema, NULL); keys = g_settings_schema_list_keys (schema); - g_assert (strv_set_equal (keys, "int32", "string", "another-int32", NULL)); + g_assert_true (strv_set_equal (keys, "int32", "string", "another-int32", NULL)); g_strfreev (keys); g_object_unref (settings); g_settings_schema_unref (schema); @@ -2818,37 +2827,37 @@ main (int argc, char *argv[]) g_remove ("org.gtk.test.enums.xml"); /* #GLIB_MKENUMS is defined in meson.build */ - g_assert (g_spawn_command_line_sync (GLIB_MKENUMS " " - "--template " SRCDIR "/enums.xml.template " - SRCDIR "/testenum.h", - &enums, NULL, &result, NULL)); - g_assert (result == 0); - g_assert (g_file_set_contents ("org.gtk.test.enums.xml", enums, -1, NULL)); + g_assert_true (g_spawn_command_line_sync (GLIB_MKENUMS " " + "--template " SRCDIR "/enums.xml.template " + SRCDIR "/testenum.h", + &enums, NULL, &result, NULL)); + g_assert_cmpint (result, ==, 0); + g_assert_true (g_file_set_contents ("org.gtk.test.enums.xml", enums, -1, NULL)); g_free (enums); - g_assert (g_file_get_contents (SRCDIR "/org.gtk.test.gschema.xml.orig", &schema_text, NULL, NULL)); - g_assert (g_file_set_contents ("org.gtk.test.gschema.xml", schema_text, -1, NULL)); + g_assert_true (g_file_get_contents (SRCDIR "/org.gtk.test.gschema.xml.orig", &schema_text, NULL, NULL)); + g_assert_true (g_file_set_contents ("org.gtk.test.gschema.xml", schema_text, -1, NULL)); g_free (schema_text); - g_assert (g_file_get_contents (SRCDIR "/org.gtk.test.gschema.override.orig", &override_text, NULL, NULL)); - g_assert (g_file_set_contents ("org.gtk.test.gschema.override", override_text, -1, NULL)); + g_assert_true (g_file_get_contents (SRCDIR "/org.gtk.test.gschema.override.orig", &override_text, NULL, NULL)); + g_assert_true (g_file_set_contents ("org.gtk.test.gschema.override", override_text, -1, NULL)); g_free (override_text); g_remove ("gschemas.compiled"); /* #GLIB_COMPILE_SCHEMAS is defined in meson.build */ - g_assert (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=. " - "--schema-file=org.gtk.test.enums.xml " - "--schema-file=org.gtk.test.gschema.xml " - "--override-file=org.gtk.test.gschema.override", - NULL, NULL, &result, NULL)); - g_assert (result == 0); + g_assert_true (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=. " + "--schema-file=org.gtk.test.enums.xml " + "--schema-file=org.gtk.test.gschema.xml " + "--override-file=org.gtk.test.gschema.override", + NULL, NULL, &result, NULL)); + g_assert_cmpint (result, ==, 0); g_remove ("schema-source/gschemas.compiled"); g_mkdir ("schema-source", 0777); - g_assert (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=schema-source " - "--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml", - NULL, NULL, &result, NULL)); - g_assert (result == 0); + g_assert_true (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=schema-source " + "--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml", + NULL, NULL, &result, NULL)); + g_assert_cmpint (result, ==, 0); g_remove ("schema-source-corrupt/gschemas.compiled"); g_mkdir ("schema-source-corrupt", 0777); diff --git a/gio/tests/gsubprocess.c b/gio/tests/gsubprocess.c index 431828384..f0b36b764 100644 --- a/gio/tests/gsubprocess.c +++ b/gio/tests/gsubprocess.c @@ -8,12 +8,20 @@ #include <gio/gfiledescriptorbased.h> #endif +/* We write 2^1 + 2^2 ... + 2^10 or 2047 copies of "Hello World!\n" + * ultimately + */ +#define TOTAL_HELLOS 2047 +#define HELLO_WORLD "hello world!\n" + #ifdef G_OS_WIN32 #define LINEEND "\r\n" #define EXEEXT ".exe" +#define SPLICELEN (TOTAL_HELLOS * (strlen (HELLO_WORLD) + 1)) /* because \r */ #else #define LINEEND "\n" #define EXEEXT +#define SPLICELEN (TOTAL_HELLOS * strlen (HELLO_WORLD)) #endif static GPtrArray * @@ -557,10 +565,7 @@ on_idle_multisplice (gpointer user_data) { TestMultiSpliceData *data = user_data; - /* We write 2^1 + 2^2 ... + 2^10 or 2047 copies of "Hello World!\n" - * ultimately - */ - if (data->counter >= 2047 || data->caught_error) + if (data->counter >= TOTAL_HELLOS || data->caught_error) { if (!g_output_stream_close (data->first_stdin, NULL, &data->error)) data->caught_error = TRUE; @@ -577,8 +582,8 @@ on_idle_multisplice (gpointer user_data) for (i = 0; i < data->counter; i++) { gsize bytes_written; - if (!g_output_stream_write_all (data->first_stdin, "hello world!\n", - strlen ("hello world!\n"), &bytes_written, + if (!g_output_stream_write_all (data->first_stdin, HELLO_WORLD, + strlen (HELLO_WORLD), &bytes_written, NULL, &data->error)) { data->caught_error = TRUE; @@ -684,7 +689,7 @@ test_multi_1 (void) g_assert (!data.caught_error); g_assert_no_error (data.error); - g_assert_cmpint (g_memory_output_stream_get_data_size ((GMemoryOutputStream*)membuf), ==, 26611); + g_assert_cmpint (g_memory_output_stream_get_data_size ((GMemoryOutputStream*)membuf), ==, SPLICELEN); g_main_loop_unref (data.loop); g_object_unref (membuf); @@ -732,7 +737,7 @@ on_communicate_complete (GObject *proc, else stdout_data = g_bytes_get_data (stdout_bytes, &stdout_len); - g_assert_cmpmem (stdout_data, stdout_len, "# hello world\n", 14); + g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND)); } else { @@ -834,7 +839,7 @@ test_communicate (gconstpointer test_data) if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE) { stdout_data = g_bytes_get_data (stdout_bytes, &stdout_len); - g_assert_cmpmem (stdout_data, stdout_len, "# hello world\n", 14); + g_assert_cmpmem (stdout_data, stdout_len, "# hello world" LINEEND, 13 + strlen (LINEEND)); } else g_assert_null (stdout_bytes); @@ -1110,7 +1115,7 @@ test_communicate_utf8 (gconstpointer test_data) g_assert_no_error (error); if (flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE) - g_assert_cmpstr (stdout_buf, ==, "# hello world\n"); + g_assert_cmpstr (stdout_buf, ==, "# hello world" LINEEND); else g_assert_null (stdout_buf); if (flags & G_SUBPROCESS_FLAGS_STDERR_PIPE) @@ -1358,9 +1363,10 @@ test_env (void) GPtrArray *args; GInputStream *stdout_stream; gchar *result; - gchar *envp[] = { "ONE=1", "TWO=1", "THREE=3", "FOUR=1", NULL }; + gchar *envp[] = { NULL, "ONE=1", "TWO=1", "THREE=3", "FOUR=1", NULL }; gchar **split; + envp[0] = g_strdup_printf ("PATH=%s", g_getenv ("PATH")); args = get_test_subprocess_args ("env", NULL); launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE); g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE); @@ -1374,11 +1380,12 @@ test_env (void) proc = g_subprocess_launcher_spawn (launcher, error, args->pdata[0], "env", NULL); g_ptr_array_free (args, TRUE); g_assert_no_error (local_error); + g_free (envp[0]); stdout_stream = g_subprocess_get_stdout_pipe (proc); result = splice_to_string (stdout_stream, error); - split = g_strsplit (result, "\n", -1); + split = g_strsplit (result, LINEEND, -1); g_assert_cmpstr (g_environ_getenv (split, "ONE"), ==, "1"); g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2"); g_assert_cmpstr (g_environ_getenv (split, "THREE"), ==, "3"); @@ -1425,7 +1432,7 @@ test_env_inherit (void) stdout_stream = g_subprocess_get_stdout_pipe (proc); result = splice_to_string (stdout_stream, error); - split = g_strsplit (result, "\n", -1); + split = g_strsplit (result, LINEEND, -1); g_assert_null (g_environ_getenv (split, "TEST_ENV_INHERIT1")); g_assert_cmpstr (g_environ_getenv (split, "TEST_ENV_INHERIT2"), ==, "2"); g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2"); @@ -1447,11 +1454,15 @@ test_cwd (void) GInputStream *stdout_stream; gchar *result; const char *basename; + gchar *tmp_lineend; + const gchar *tmp_lineend_basename; args = get_test_subprocess_args ("cwd", NULL); launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE); - g_subprocess_launcher_set_cwd (launcher, "/tmp"); + g_subprocess_launcher_set_cwd (launcher, g_get_tmp_dir ()); + tmp_lineend = g_strdup_printf ("%s%s", g_get_tmp_dir (), LINEEND); + tmp_lineend_basename = g_strrstr (tmp_lineend, G_DIR_SEPARATOR_S); proc = g_subprocess_launcher_spawnv (launcher, (const char * const *)args->pdata, error); g_ptr_array_free (args, TRUE); @@ -1461,9 +1472,10 @@ test_cwd (void) result = splice_to_string (stdout_stream, error); - basename = g_strrstr (result, "/"); + basename = g_strrstr (result, G_DIR_SEPARATOR_S); g_assert (basename != NULL); - g_assert_cmpstr (basename, ==, "/tmp" LINEEND); + g_assert_cmpstr (basename, ==, tmp_lineend_basename); + g_free (tmp_lineend); g_free (result); g_object_unref (proc); @@ -1719,7 +1731,7 @@ test_launcher_environment (void) g_subprocess_communicate_utf8 (proc, NULL, NULL, &out, NULL, &error); g_assert_no_error (error); - g_assert_cmpstr (out, ==, "C=D\nE=F\n"); + g_assert_cmpstr (out, ==, "C=D" LINEEND "E=F" LINEEND); g_free (out); g_object_unref (proc); diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 8bf555cf2..a1b41872d 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -55,7 +55,7 @@ gio_tests = { 'memory-output-stream' : {}, 'monitor' : {}, 'mount-operation' : {}, - 'network-address' : {'extra_sources': ['mock-resolver.c'], 'suite': ['flaky']}, + 'network-address' : {'extra_sources': ['mock-resolver.c']}, 'network-monitor' : {}, 'network-monitor-race' : {}, 'permission' : {}, @@ -67,7 +67,7 @@ gio_tests = { 'sleepy-stream' : {}, 'socket' : {}, 'socket-listener' : {}, - 'socket-service' : {}, + 'socket-service' : { 'suite': ['flaky'] }, 'srvtarget' : {}, 'task' : {}, 'vfs' : {}, @@ -140,11 +140,16 @@ if host_machine.system() != 'windows' 'slow-connect-preload.c', name_prefix : '', dependencies: cc.find_library('dl'), + install_dir : installed_tests_execdir, + install: installed_tests_enabled, ) ], 'env' : { 'LD_PRELOAD': '@0@/slow-connect-preload.so'.format(meson.current_build_dir()) }, + 'installed_tests_env' : { + 'LD_PRELOAD': '@0@/slow-connect-preload.so'.format(installed_tests_execdir), + }, 'suite': ['flaky'], }, 'gschema-compile' : {'install' : false}, @@ -428,6 +433,7 @@ if installed_tests_enabled 'appinfo-test-static.desktop', 'file.c', 'org.gtk.test.dbusappinfo.desktop', + 'test1.overlay', install_dir : installed_tests_execdir, ) install_subdir('x-content', install_dir : installed_tests_execdir) @@ -592,11 +598,21 @@ foreach test_name, extra_args : gio_tests source = extra_args.get('source', test_name + '.c') extra_sources = extra_args.get('extra_sources', []) install = installed_tests_enabled and extra_args.get('install', true) + installed_tests_env = extra_args.get('installed_tests_env', {}) if install test_conf = configuration_data() test_conf.set('installed_tests_dir', installed_tests_execdir) test_conf.set('program', test_name) + test_env_override = '' + if installed_tests_env != {} + envs = [] + foreach var, value : installed_tests_env + envs += '@0@=@1@'.format(var, value) + endforeach + test_env_override = '@0@ @1@ '.format(env_program.path(), ' '.join(envs)) + endif + test_conf.set('env', test_env_override) configure_file( input: installed_tests_template_tap, output: test_name + '.test', diff --git a/gio/tests/network-address.c b/gio/tests/network-address.c index 4a2718e24..c62afccd2 100644 --- a/gio/tests/network-address.c +++ b/gio/tests/network-address.c @@ -271,6 +271,7 @@ find_ifname_and_index (void) static void test_scope_id (GSocketConnectable *addr) { +#ifndef G_OS_WIN32 GSocketAddressEnumerator *addr_enum; GSocketAddress *saddr; GInetSocketAddress *isaddr; @@ -300,6 +301,9 @@ test_scope_id (GSocketConnectable *addr) g_assert (saddr == NULL); g_object_unref (addr_enum); +#else + g_test_skip ("winsock2 getaddrinfo() can’t understand scope IDs"); +#endif } static void @@ -622,13 +626,16 @@ happy_eyeballs_teardown (HappyEyeballsFixture *fixture, g_main_loop_unref (fixture->loop); } +static const guint FAST_DELAY_LESS_THAN_TIMEOUT = 25; +static const guint SLOW_DELAY_MORE_THAN_TIMEOUT = 100; + static void test_happy_eyeballs_basic (HappyEyeballsFixture *fixture, gconstpointer user_data) { AsyncData data = { 0 }; - data.delay_ms = 10; + data.delay_ms = FAST_DELAY_LESS_THAN_TIMEOUT; data.loop = fixture->loop; /* This just tests in the common case it gets all results */ @@ -645,15 +652,15 @@ test_happy_eyeballs_slow_ipv4 (HappyEyeballsFixture *fixture, { AsyncData data = { 0 }; - /* If ipv4 dns response is a bit slow we just don't get them */ + /* If ipv4 dns response is a bit slow we still get everything */ data.loop = fixture->loop; - mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, 25); + mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); - assert_list_matches_expected (data.addrs, fixture->input_ipv6_results); + assert_list_matches_expected (data.addrs, fixture->input_all_results); } static void @@ -665,7 +672,7 @@ test_happy_eyeballs_slow_ipv6 (HappyEyeballsFixture *fixture, /* If ipv6 is a bit slow it waits for them */ data.loop = fixture->loop; - mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, 25); + mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); @@ -679,15 +686,15 @@ test_happy_eyeballs_very_slow_ipv6 (HappyEyeballsFixture *fixture, { AsyncData data = { 0 }; - /* If ipv6 is very slow we don't get them */ + /* If ipv6 is very slow we still get everything */ data.loop = fixture->loop; - mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, 200); + mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); - assert_list_matches_expected (data.addrs, fixture->input_ipv4_results); + assert_list_matches_expected (data.addrs, fixture->input_all_results); } static void @@ -700,8 +707,8 @@ test_happy_eyeballs_slow_connection_and_ipv4 (HappyEyeballsFixture *fixture, * take long enough. */ data.loop = fixture->loop; - data.delay_ms = 500; - mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, 200); + data.delay_ms = SLOW_DELAY_MORE_THAN_TIMEOUT * 2; + mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); @@ -710,17 +717,18 @@ test_happy_eyeballs_slow_connection_and_ipv4 (HappyEyeballsFixture *fixture, } static void -test_happy_eyeballs_ipv6_error (HappyEyeballsFixture *fixture, - gconstpointer user_data) +test_happy_eyeballs_ipv6_error_ipv4_first (HappyEyeballsFixture *fixture, + gconstpointer user_data) { AsyncData data = { 0 }; GError *ipv6_error; - /* If ipv6 fails we still get ipv4. */ + /* If ipv6 fails, ensuring that ipv4 finishes before ipv6 errors, we still get ipv4. */ data.loop = fixture->loop; ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken"); mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error); + mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); @@ -731,17 +739,62 @@ test_happy_eyeballs_ipv6_error (HappyEyeballsFixture *fixture, } static void -test_happy_eyeballs_ipv4_error (HappyEyeballsFixture *fixture, - gconstpointer user_data) +test_happy_eyeballs_ipv6_error_ipv6_first (HappyEyeballsFixture *fixture, + gconstpointer user_data) +{ + AsyncData data = { 0 }; + GError *ipv6_error; + + /* If ipv6 fails, ensuring that ipv6 errors before ipv4 finishes, we still get ipv4. */ + + data.loop = fixture->loop; + ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken"); + mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error); + mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); + + g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); + g_main_loop_run (fixture->loop); + + assert_list_matches_expected (data.addrs, fixture->input_ipv4_results); + + g_error_free (ipv6_error); +} + +static void +test_happy_eyeballs_ipv4_error_ipv4_first (HappyEyeballsFixture *fixture, + gconstpointer user_data) +{ + AsyncData data = { 0 }; + GError *ipv4_error; + + /* If ipv4 fails, ensuring that ipv4 errors before ipv6 finishes, we still get ipv6. */ + + data.loop = fixture->loop; + ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken"); + mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error); + mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); + + g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); + g_main_loop_run (fixture->loop); + + assert_list_matches_expected (data.addrs, fixture->input_ipv6_results); + + g_error_free (ipv4_error); +} + +static void +test_happy_eyeballs_ipv4_error_ipv6_first (HappyEyeballsFixture *fixture, + gconstpointer user_data) { AsyncData data = { 0 }; GError *ipv4_error; - /* If ipv4 fails we still get ipv6. */ + /* If ipv4 fails, ensuring that ipv6 finishes before ipv4 errors, we still get ipv6. */ data.loop = fixture->loop; ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken"); mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error); + mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); @@ -792,7 +845,7 @@ test_happy_eyeballs_both_error_delays_1 (HappyEyeballsFixture *fixture, ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken"); mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error); - mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, 25); + mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); @@ -820,7 +873,7 @@ test_happy_eyeballs_both_error_delays_2 (HappyEyeballsFixture *fixture, mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error); mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error); - mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, 25); + mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); @@ -847,7 +900,7 @@ test_happy_eyeballs_both_error_delays_3 (HappyEyeballsFixture *fixture, mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error); mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error); - mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, 200); + mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT); g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data); g_main_loop_run (fixture->loop); @@ -913,10 +966,14 @@ main (int argc, char *argv[]) happy_eyeballs_setup, test_happy_eyeballs_very_slow_ipv6, happy_eyeballs_teardown); g_test_add ("/network-address/happy-eyeballs/slow-connection-and-ipv4", HappyEyeballsFixture, NULL, happy_eyeballs_setup, test_happy_eyeballs_slow_connection_and_ipv4, happy_eyeballs_teardown); - g_test_add ("/network-address/happy-eyeballs/ipv6-error", HappyEyeballsFixture, NULL, - happy_eyeballs_setup, test_happy_eyeballs_ipv6_error, happy_eyeballs_teardown); - g_test_add ("/network-address/happy-eyeballs/ipv4-error", HappyEyeballsFixture, NULL, - happy_eyeballs_setup, test_happy_eyeballs_ipv4_error, happy_eyeballs_teardown); + g_test_add ("/network-address/happy-eyeballs/ipv6-error-ipv4-first", HappyEyeballsFixture, NULL, + happy_eyeballs_setup, test_happy_eyeballs_ipv6_error_ipv4_first, happy_eyeballs_teardown); + g_test_add ("/network-address/happy-eyeballs/ipv6-error-ipv6-first", HappyEyeballsFixture, NULL, + happy_eyeballs_setup, test_happy_eyeballs_ipv6_error_ipv6_first, happy_eyeballs_teardown); + g_test_add ("/network-address/happy-eyeballs/ipv4-error-ipv6-first", HappyEyeballsFixture, NULL, + happy_eyeballs_setup, test_happy_eyeballs_ipv4_error_ipv6_first, happy_eyeballs_teardown); + g_test_add ("/network-address/happy-eyeballs/ipv4-error-ipv4-first", HappyEyeballsFixture, NULL, + happy_eyeballs_setup, test_happy_eyeballs_ipv4_error_ipv4_first, happy_eyeballs_teardown); g_test_add ("/network-address/happy-eyeballs/both-error", HappyEyeballsFixture, NULL, happy_eyeballs_setup, test_happy_eyeballs_both_error, happy_eyeballs_teardown); g_test_add ("/network-address/happy-eyeballs/both-error-delays-1", HappyEyeballsFixture, NULL, diff --git a/gio/tests/task.c b/gio/tests/task.c index db1b2d4fe..9f7ae2563 100644 --- a/gio/tests/task.c +++ b/gio/tests/task.c @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat, Inc. + * Copyright 2012-2019 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -654,6 +654,151 @@ name_callback (GObject *object, g_main_loop_quit (loop); } +/* test_asynchronous_cancellation: cancelled tasks are returned + * asynchronously, i.e. not from inside the GCancellable::cancelled + * handler. + * + * The test is set up further below in test_asynchronous_cancellation. + */ + +/* asynchronous_cancellation_callback represents the callback that the + * caller of a typical asynchronous API would have passed. See + * test_asynchronous_cancellation. + */ +static void +asynchronous_cancellation_callback (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GError *error = NULL; + guint run_task_id; + + g_assert_null (object); + g_assert_true (g_task_is_valid (result, object)); + g_assert_true (g_async_result_get_user_data (result) == user_data); + g_assert_true (g_task_had_error (G_TASK (result))); + g_assert_false (g_task_get_completed (G_TASK (result))); + + run_task_id = GPOINTER_TO_UINT (g_task_get_task_data (G_TASK (result))); + g_assert_cmpuint (run_task_id, ==, 0); + + g_task_propagate_boolean (G_TASK (result), &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_clear_error (&error); + + g_assert_true (g_task_had_error (G_TASK (result))); + + g_main_loop_quit (loop); +} + +/* asynchronous_cancellation_cancel_task represents a user cancelling + * the ongoing operation. To make it somewhat realistic it is delayed + * by 50ms via a timeout GSource. See test_asynchronous_cancellation. + */ +static gboolean +asynchronous_cancellation_cancel_task (gpointer user_data) +{ + GCancellable *cancellable; + GTask *task = G_TASK (user_data); + + cancellable = g_task_get_cancellable (task); + g_assert_true (G_IS_CANCELLABLE (cancellable)); + + g_cancellable_cancel (cancellable); + g_assert_false (g_task_get_completed (task)); + + return G_SOURCE_REMOVE; +} + +/* asynchronous_cancellation_cancelled is the GCancellable::cancelled + * handler that's used by the asynchronous implementation for + * cancelling itself. + */ +static void +asynchronous_cancellation_cancelled (GCancellable *cancellable, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + guint run_task_id; + + g_assert_true (cancellable == g_task_get_cancellable (task)); + + run_task_id = GPOINTER_TO_UINT (g_task_get_task_data (task)); + g_assert_cmpuint (run_task_id, !=, 0); + + g_source_remove (run_task_id); + g_task_set_task_data (task, GUINT_TO_POINTER (0), NULL); + + g_task_return_boolean (task, FALSE); + g_assert_false (g_task_get_completed (task)); +} + +/* asynchronous_cancellation_run_task represents the actual + * asynchronous work being done in an idle GSource as was mentioned + * above. This is effectively meant to be an infinite loop so that + * the only way to break out of it is via cancellation. + */ +static gboolean +asynchronous_cancellation_run_task (gpointer user_data) +{ + GCancellable *cancellable; + GTask *task = G_TASK (user_data); + + cancellable = g_task_get_cancellable (task); + g_assert_true (G_IS_CANCELLABLE (cancellable)); + g_assert_false (g_cancellable_is_cancelled (cancellable)); + + return G_SOURCE_CONTINUE; +} + +/* Test that cancellation is always asynchronous. The completion callback for + * a #GTask must not be called from inside the cancellation handler. + * + * The body of the loop inside test_asynchronous_cancellation + * represents what would have been a typical asynchronous API call, + * and its implementation. They are fused together without an API + * boundary. The actual work done by this asynchronous API is + * represented by an idle GSource. + */ +static void +test_asynchronous_cancellation (void) +{ + guint i; + + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1608"); + + /* Run a few times to shake out any timing issues between the + * cancellation and task sources. + */ + for (i = 0; i < 5; i++) + { + GCancellable *cancellable; + GTask *task; + gboolean notification_emitted = FALSE; + guint run_task_id; + + cancellable = g_cancellable_new (); + + task = g_task_new (NULL, cancellable, asynchronous_cancellation_callback, NULL); + g_cancellable_connect (cancellable, (GCallback) asynchronous_cancellation_cancelled, task, NULL); + g_signal_connect (task, "notify::completed", (GCallback) completed_cb, ¬ification_emitted); + + run_task_id = g_idle_add (asynchronous_cancellation_run_task, task); + g_source_set_name_by_id (run_task_id, "[test_asynchronous_cancellation] run_task"); + g_task_set_task_data (task, GUINT_TO_POINTER (run_task_id), NULL); + + g_timeout_add (50, asynchronous_cancellation_cancel_task, task); + + g_main_loop_run (loop); + + g_assert_true (g_task_get_completed (task)); + g_assert_true (notification_emitted); + + g_object_unref (cancellable); + g_object_unref (task); + } +} + /* test_check_cancellable: cancellation overrides return value */ enum { @@ -2186,6 +2331,7 @@ main (int argc, char **argv) g_test_add_func ("/gtask/report-error", test_report_error); g_test_add_func ("/gtask/priority", test_priority); g_test_add_func ("/gtask/name", test_name); + g_test_add_func ("/gtask/asynchronous-cancellation", test_asynchronous_cancellation); g_test_add_func ("/gtask/check-cancellable", test_check_cancellable); g_test_add_func ("/gtask/return-if-cancelled", test_return_if_cancelled); g_test_add_func ("/gtask/run-in-thread", test_run_in_thread); diff --git a/gio/win32/gwinhttpvfs.c b/gio/win32/gwinhttpvfs.c index d32a4cbe1..038368f81 100644 --- a/gio/win32/gwinhttpvfs.c +++ b/gio/win32/gwinhttpvfs.c @@ -173,7 +173,7 @@ g_winhttp_vfs_get_file_for_uri (GVfs *vfs, return _g_winhttp_file_new (winhttp_vfs, uri); /* For other URIs fallback to the wrapped GVfs */ - return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, uri); + return g_vfs_get_file_for_uri (winhttp_vfs->wrapped_vfs, uri); } static const gchar * const * |