mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-09 19:06:15 +01:00
GSocketClient: add proxy-resolver property
Add a proxy-resolver property to GSocketClient, to allow overriding proxy resolution in situations where you need to force a particular proxy rather than using the system defaults. https://bugzilla.gnome.org/show_bug.cgi?id=691105
This commit is contained in:
parent
d200208d2b
commit
7c49869eae
@ -1958,6 +1958,7 @@ g_socket_client_set_protocol
|
||||
g_socket_client_set_socket_type
|
||||
g_socket_client_set_timeout
|
||||
g_socket_client_set_enable_proxy
|
||||
g_socket_client_set_proxy_resolver
|
||||
g_socket_client_set_tls
|
||||
g_socket_client_set_tls_validation_flags
|
||||
g_socket_client_get_family
|
||||
@ -1966,6 +1967,7 @@ g_socket_client_get_protocol
|
||||
g_socket_client_get_socket_type
|
||||
g_socket_client_get_timeout
|
||||
g_socket_client_get_enable_proxy
|
||||
g_socket_client_get_proxy_resolver
|
||||
g_socket_client_get_tls
|
||||
g_socket_client_get_tls_validation_flags
|
||||
g_socket_client_add_application_proxy
|
||||
|
@ -47,7 +47,8 @@ enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_URI,
|
||||
PROP_CONNECTABLE
|
||||
PROP_CONNECTABLE,
|
||||
PROP_PROXY_RESOLVER
|
||||
};
|
||||
|
||||
struct _GProxyAddressEnumeratorPrivate
|
||||
@ -60,6 +61,7 @@ struct _GProxyAddressEnumeratorPrivate
|
||||
GList *dest_ips;
|
||||
|
||||
/* Proxy enumeration */
|
||||
GProxyResolver *proxy_resolver;
|
||||
gchar **proxies;
|
||||
gchar **next_proxy;
|
||||
GSocketAddressEnumerator *addr_enum;
|
||||
@ -180,8 +182,7 @@ g_proxy_address_enumerator_next (GSocketAddressEnumerator *enumerator,
|
||||
|
||||
if (priv->proxies == NULL)
|
||||
{
|
||||
GProxyResolver *resolver = g_proxy_resolver_get_default ();
|
||||
priv->proxies = g_proxy_resolver_lookup (resolver,
|
||||
priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
|
||||
priv->dest_uri,
|
||||
cancellable,
|
||||
error);
|
||||
@ -530,8 +531,7 @@ g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
|
||||
|
||||
if (priv->proxies == NULL)
|
||||
{
|
||||
GProxyResolver *resolver = g_proxy_resolver_get_default ();
|
||||
g_proxy_resolver_lookup_async (resolver,
|
||||
g_proxy_resolver_lookup_async (priv->proxy_resolver,
|
||||
priv->dest_uri,
|
||||
cancellable,
|
||||
proxy_lookup_cb,
|
||||
@ -586,6 +586,10 @@ g_proxy_address_enumerator_get_property (GObject *object,
|
||||
g_value_set_object (value, priv->connectable);
|
||||
break;
|
||||
|
||||
case PROP_PROXY_RESOLVER:
|
||||
g_value_set_object (value, priv->proxy_resolver);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
@ -643,6 +647,15 @@ g_proxy_address_enumerator_set_property (GObject *object,
|
||||
priv->connectable = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_PROXY_RESOLVER:
|
||||
if (priv->proxy_resolver)
|
||||
g_object_unref (priv->proxy_resolver);
|
||||
priv->proxy_resolver = g_value_get_object (value);
|
||||
if (!priv->proxy_resolver)
|
||||
priv->proxy_resolver = g_proxy_resolver_get_default ();
|
||||
g_object_ref (priv->proxy_resolver);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
@ -656,6 +669,9 @@ g_proxy_address_enumerator_finalize (GObject *object)
|
||||
if (priv->connectable)
|
||||
g_object_unref (priv->connectable);
|
||||
|
||||
if (priv->proxy_resolver)
|
||||
g_object_unref (priv->proxy_resolver);
|
||||
|
||||
g_free (priv->dest_uri);
|
||||
g_free (priv->dest_hostname);
|
||||
|
||||
@ -720,4 +736,21 @@ g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enume
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GProxyAddressEnumerator:proxy-resolver:
|
||||
*
|
||||
* The proxy resolver to use.
|
||||
*
|
||||
* Since: 2.36
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PROXY_RESOLVER,
|
||||
g_param_spec_object ("proxy-resolver",
|
||||
P_("Proxy resolver"),
|
||||
P_("The proxy resolver to use."),
|
||||
G_TYPE_PROXY_RESOLVER,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <gio/gnetworkaddress.h>
|
||||
#include <gio/gnetworkservice.h>
|
||||
#include <gio/gproxy.h>
|
||||
#include <gio/gproxyresolver.h>
|
||||
#include <gio/gsocketaddress.h>
|
||||
#include <gio/gtcpconnection.h>
|
||||
#include <gio/gtcpwrapperconnection.h>
|
||||
@ -94,7 +95,8 @@ enum
|
||||
PROP_TIMEOUT,
|
||||
PROP_ENABLE_PROXY,
|
||||
PROP_TLS,
|
||||
PROP_TLS_VALIDATION_FLAGS
|
||||
PROP_TLS_VALIDATION_FLAGS,
|
||||
PROP_PROXY_RESOLVER
|
||||
};
|
||||
|
||||
struct _GSocketClientPrivate
|
||||
@ -108,6 +110,7 @@ struct _GSocketClientPrivate
|
||||
GHashTable *app_proxies;
|
||||
gboolean tls;
|
||||
GTlsCertificateFlags tls_validation_flags;
|
||||
GProxyResolver *proxy_resolver;
|
||||
};
|
||||
|
||||
static GSocket *
|
||||
@ -227,8 +230,8 @@ g_socket_client_finalize (GObject *object)
|
||||
{
|
||||
GSocketClient *client = G_SOCKET_CLIENT (object);
|
||||
|
||||
if (client->priv->local_address)
|
||||
g_object_unref (client->priv->local_address);
|
||||
g_clear_object (&client->priv->local_address);
|
||||
g_clear_object (&client->priv->proxy_resolver);
|
||||
|
||||
if (G_OBJECT_CLASS (g_socket_client_parent_class)->finalize)
|
||||
(*G_OBJECT_CLASS (g_socket_client_parent_class)->finalize) (object);
|
||||
@ -278,6 +281,10 @@ g_socket_client_get_property (GObject *object,
|
||||
g_value_set_flags (value, g_socket_client_get_tls_validation_flags (client));
|
||||
break;
|
||||
|
||||
case PROP_PROXY_RESOLVER:
|
||||
g_value_set_object (value, g_socket_client_get_proxy_resolver (client));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@ -325,6 +332,10 @@ g_socket_client_set_property (GObject *object,
|
||||
g_socket_client_set_tls_validation_flags (client, g_value_get_flags (value));
|
||||
break;
|
||||
|
||||
case PROP_PROXY_RESOLVER:
|
||||
g_socket_client_set_proxy_resolver (client, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@ -579,6 +590,8 @@ g_socket_client_get_enable_proxy (GSocketClient *client)
|
||||
* #GProxyResolver to determine if a proxy protocol such as SOCKS is
|
||||
* needed, and automatically do the necessary proxy negotiation.
|
||||
*
|
||||
* See also g_socket_client_set_proxy_resolver().
|
||||
*
|
||||
* Since: 2.26
|
||||
*/
|
||||
void
|
||||
@ -686,6 +699,64 @@ g_socket_client_set_tls_validation_flags (GSocketClient *client,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_client_get_proxy_resolver:
|
||||
* @client: a #GSocketClient.
|
||||
*
|
||||
* Gets the #GProxyResolver being used by @client. Normally, this will
|
||||
* be the resolver returned by g_proxy_resolver_get_default(), but you
|
||||
* can override it with g_socket_client_set_proxy_resolver().
|
||||
*
|
||||
* Returns: (transfer none): The #GProxyResolver being used by
|
||||
* @client.
|
||||
*
|
||||
* Since: 2.36
|
||||
*/
|
||||
GProxyResolver *
|
||||
g_socket_client_get_proxy_resolver (GSocketClient *client)
|
||||
{
|
||||
if (client->priv->proxy_resolver)
|
||||
return client->priv->proxy_resolver;
|
||||
else
|
||||
return g_proxy_resolver_get_default ();
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_client_set_proxy_resolver:
|
||||
* @client: a #GSocketClient.
|
||||
* @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL for the
|
||||
* default.
|
||||
*
|
||||
* Overrides the #GProxyResolver used by @client. You can call this if
|
||||
* you want to use specific proxies, rather than using the system
|
||||
* default proxy settings.
|
||||
*
|
||||
* Note that whether or not the proxy resolver is actually used
|
||||
* depends on the setting of #GSocketClient:enable-proxy, which is not
|
||||
* changed by this function (but which is %TRUE by default)
|
||||
*
|
||||
* Since: 2.36
|
||||
*/
|
||||
void
|
||||
g_socket_client_set_proxy_resolver (GSocketClient *client,
|
||||
GProxyResolver *proxy_resolver)
|
||||
{
|
||||
/* We have to be careful to avoid calling
|
||||
* g_proxy_resolver_get_default() until we're sure we need it,
|
||||
* because trying to load the default proxy resolver module will
|
||||
* break some test programs that aren't expecting it (eg,
|
||||
* tests/gsettings).
|
||||
*/
|
||||
|
||||
if (client->priv->proxy_resolver)
|
||||
g_object_unref (client->priv->proxy_resolver);
|
||||
|
||||
client->priv->proxy_resolver = proxy_resolver;
|
||||
|
||||
if (client->priv->proxy_resolver)
|
||||
g_object_ref (client->priv->proxy_resolver);
|
||||
}
|
||||
|
||||
static void
|
||||
g_socket_client_class_init (GSocketClientClass *class)
|
||||
{
|
||||
@ -881,6 +952,22 @@ g_socket_client_class_init (GSocketClientClass *class)
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GSocketClient:proxy-resolver:
|
||||
*
|
||||
* The proxy resolver to use
|
||||
*
|
||||
* Since: 2.36
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
|
||||
g_param_spec_object ("proxy-resolver",
|
||||
P_("Proxy resolver"),
|
||||
P_("The proxy resolver to use"),
|
||||
G_TYPE_PROXY_RESOLVER,
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -936,7 +1023,15 @@ g_socket_client_connect (GSocketClient *client,
|
||||
last_error = NULL;
|
||||
|
||||
if (can_use_proxy (client))
|
||||
enumerator = g_socket_connectable_proxy_enumerate (connectable);
|
||||
{
|
||||
enumerator = g_socket_connectable_proxy_enumerate (connectable);
|
||||
if (client->priv->proxy_resolver &&
|
||||
G_IS_PROXY_ADDRESS_ENUMERATOR (enumerator))
|
||||
{
|
||||
g_object_set (G_OBJECT (enumerator), "proxy-resolver",
|
||||
client->priv->proxy_resolver);
|
||||
}
|
||||
}
|
||||
else
|
||||
enumerator = g_socket_connectable_enumerate (connectable);
|
||||
|
||||
@ -1605,9 +1700,17 @@ g_socket_client_connect_async (GSocketClient *client,
|
||||
data->connectable = g_object_ref (connectable);
|
||||
|
||||
if (can_use_proxy (client))
|
||||
{
|
||||
data->enumerator = g_socket_connectable_proxy_enumerate (connectable);
|
||||
if (client->priv->proxy_resolver &&
|
||||
G_IS_PROXY_ADDRESS_ENUMERATOR (data->enumerator))
|
||||
{
|
||||
g_object_set (G_OBJECT (data->enumerator), "proxy-resolver",
|
||||
client->priv->proxy_resolver);
|
||||
}
|
||||
}
|
||||
else
|
||||
data->enumerator = g_socket_connectable_enumerate (connectable);
|
||||
data->enumerator = g_socket_connectable_enumerate (connectable);
|
||||
|
||||
data->task = g_task_new (client, cancellable, callback, user_data);
|
||||
g_task_set_task_data (data->task, data, (GDestroyNotify)g_socket_client_async_connect_data_free);
|
||||
|
@ -117,6 +117,11 @@ GTlsCertificateFlags g_socket_client_get_tls_validation_flags (GSocket
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_socket_client_set_tls_validation_flags (GSocketClient *client,
|
||||
GTlsCertificateFlags flags);
|
||||
GLIB_AVAILABLE_IN_2_36
|
||||
GProxyResolver *g_socket_client_get_proxy_resolver (GSocketClient *client);
|
||||
GLIB_AVAILABLE_IN_2_36
|
||||
void g_socket_client_set_proxy_resolver (GSocketClient *client,
|
||||
GProxyResolver *proxy_resolver);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GSocketConnection * g_socket_client_connect (GSocketClient *client,
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Overview:
|
||||
*
|
||||
* We have an echo server, two proxy servers, two GProxy
|
||||
* implementations, and a GProxyResolver implementation.
|
||||
* implementations, and two GProxyResolver implementations.
|
||||
*
|
||||
* The echo server runs at @server.server_addr (on
|
||||
* @server.server_port).
|
||||
@ -42,9 +42,10 @@
|
||||
* hostname resolution (but it just ignores the hostname and always
|
||||
* connects to @server_addr anyway).
|
||||
*
|
||||
* The GProxyResolver (GTestProxyResolver) looks at its URI and
|
||||
* returns [ "direct://" ] for "simple://" URIs, and [ proxy_a.uri,
|
||||
* proxy_b.uri ] for other URIs.
|
||||
* The default GProxyResolver (GTestProxyResolver) looks at its URI
|
||||
* and returns [ "direct://" ] for "simple://" URIs, and [
|
||||
* proxy_a.uri, proxy_b.uri ] for other URIs. The other GProxyResolver
|
||||
* (GTestAltProxyResolver) always returns [ proxy_a.uri ].
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
@ -163,7 +164,7 @@ g_test_proxy_resolver_lookup_async (GProxyResolver *resolver,
|
||||
GTask *task;
|
||||
gchar **proxies;
|
||||
|
||||
proxies = g_test_proxy_resolver_lookup (resolver, uri, cancellable, &error);
|
||||
proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
|
||||
|
||||
task = g_task_new (resolver, NULL, callback, user_data);
|
||||
if (proxies == NULL)
|
||||
@ -196,6 +197,56 @@ g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
|
||||
iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
|
||||
}
|
||||
|
||||
/****************************/
|
||||
/* Alternate GProxyResolver */
|
||||
/****************************/
|
||||
|
||||
typedef GTestProxyResolver GTestAltProxyResolver;
|
||||
typedef GTestProxyResolverClass GTestAltProxyResolverClass;
|
||||
|
||||
static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface);
|
||||
|
||||
static GType _g_test_alt_proxy_resolver_get_type (void);
|
||||
#define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type
|
||||
G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (),
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
|
||||
g_test_alt_proxy_resolver_iface_init);
|
||||
)
|
||||
|
||||
static void
|
||||
g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver)
|
||||
{
|
||||
}
|
||||
|
||||
static gchar **
|
||||
g_test_alt_proxy_resolver_lookup (GProxyResolver *resolver,
|
||||
const gchar *uri,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gchar **proxies;
|
||||
|
||||
proxies = g_new (gchar *, 2);
|
||||
|
||||
proxies[0] = g_strdup (proxy_a.uri);
|
||||
proxies[1] = NULL;
|
||||
|
||||
last_proxies = g_strdupv (proxies);
|
||||
|
||||
return proxies;
|
||||
}
|
||||
|
||||
static void
|
||||
g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface)
|
||||
{
|
||||
iface->lookup = g_test_alt_proxy_resolver_lookup;
|
||||
}
|
||||
|
||||
|
||||
/****************************************/
|
||||
/* Test proxy implementation base class */
|
||||
@ -1093,6 +1144,98 @@ test_dns (gpointer fixture,
|
||||
teardown_test (NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
assert_override (GSocketConnection *conn)
|
||||
{
|
||||
g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
|
||||
g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
|
||||
|
||||
if (conn)
|
||||
g_assert_no_error (proxy_a.last_error);
|
||||
else
|
||||
g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static void
|
||||
test_override (gpointer fixture,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
GProxyResolver *alt_resolver;
|
||||
GSocketConnection *conn;
|
||||
GError *error = NULL;
|
||||
gchar *uri;
|
||||
|
||||
g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
|
||||
alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL);
|
||||
g_socket_client_set_proxy_resolver (client, alt_resolver);
|
||||
g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
|
||||
|
||||
/* Alt proxy resolver always returns Proxy A, so alpha:// should
|
||||
* succeed, and simple:// and beta:// should fail.
|
||||
*/
|
||||
|
||||
/* simple */
|
||||
uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
|
||||
conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||||
g_clear_error (&error);
|
||||
assert_override (conn);
|
||||
teardown_test (NULL, NULL);
|
||||
|
||||
g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
|
||||
async_got_error, &error);
|
||||
while (error == NULL)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||||
g_clear_error (&error);
|
||||
assert_override (conn);
|
||||
g_free (uri);
|
||||
teardown_test (NULL, NULL);
|
||||
|
||||
/* alpha */
|
||||
uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
|
||||
conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
assert_override (conn);
|
||||
do_echo_test (conn);
|
||||
g_clear_object (&conn);
|
||||
teardown_test (NULL, NULL);
|
||||
|
||||
conn = NULL;
|
||||
g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
|
||||
async_got_conn, &conn);
|
||||
while (conn == NULL)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
assert_override (conn);
|
||||
do_echo_test (conn);
|
||||
g_clear_object (&conn);
|
||||
g_free (uri);
|
||||
teardown_test (NULL, NULL);
|
||||
|
||||
/* beta */
|
||||
uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
|
||||
conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||||
g_clear_error (&error);
|
||||
assert_override (conn);
|
||||
teardown_test (NULL, NULL);
|
||||
|
||||
g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
|
||||
async_got_error, &error);
|
||||
while (error == NULL)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
|
||||
g_clear_error (&error);
|
||||
assert_override (conn);
|
||||
g_free (uri);
|
||||
teardown_test (NULL, NULL);
|
||||
|
||||
g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
|
||||
g_socket_client_set_proxy_resolver (client, NULL);
|
||||
g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
|
||||
g_object_unref (alt_resolver);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -1132,6 +1275,7 @@ main (int argc,
|
||||
g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
|
||||
g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
|
||||
g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
|
||||
g_test_add_vtable ("/proxy/override", 0, NULL, setup_test, test_override, teardown_test);
|
||||
|
||||
result = g_test_run();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user