mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 07:56:17 +01:00
Merge branch '3303-girepository-typelib-determinicity' into 'main'
girepository: Keep an ordered list of the loaded typelibs Closes #3303 See merge request GNOME/glib!4033
This commit is contained in:
commit
5433bb23a0
@ -65,6 +65,23 @@
|
||||
* The environment variable takes precedence over the default search path
|
||||
* and the [method@GIRepository.Repository.prepend_search_path] calls.
|
||||
*
|
||||
* ### Namespace ordering
|
||||
*
|
||||
* In situations where namespaces may be searched in order, or returned in a
|
||||
* list, the namespaces will be returned in alphabetical order, with all fully
|
||||
* loaded namespaces being returned before any lazily loaded ones (those loaded
|
||||
* with `GI_REPOSITORY_LOAD_FLAG_LAZY`). This allows for deterministic and
|
||||
* reproducible results.
|
||||
*
|
||||
* Similarly, if a symbol (such as a `GType` or error domain) is being searched
|
||||
* for in the set of loaded namespaces, the namespaces will be searched in that
|
||||
* order. In particular, this means that a symbol which exists in two namespaces
|
||||
* will always be returned from the alphabetically-higher namespace. This should
|
||||
* only happen in the case of `Gio` and `GioUnix`/`GioWin32`, which all refer to
|
||||
* the same `.so` file and expose overlapping sets of symbols. Symbols should
|
||||
* always end up being resolved to `GioUnix` or `GioWin32` if they are platform
|
||||
* dependent, rather than `Gio` itself.
|
||||
*
|
||||
* Since: 2.80
|
||||
*/
|
||||
|
||||
@ -98,8 +115,14 @@ struct _GIRepository
|
||||
GPtrArray *typelib_search_path; /* (element-type filename) (owned) */
|
||||
GPtrArray *library_paths; /* (element-type filename) (owned) */
|
||||
|
||||
/* Certain operations require iterating over the typelibs and the iteration
|
||||
* order may affect the results. So keep an ordered list of the typelibs,
|
||||
* alongside the hash table which keep the canonical strong reference to them. */
|
||||
GHashTable *typelibs; /* (string) namespace -> GITypelib */
|
||||
GPtrArray *ordered_typelibs; /* (element-type unowned GITypelib) (owned) (not nullable) */
|
||||
GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */
|
||||
GPtrArray *ordered_lazy_typelibs; /* (element-type unowned GITypelib) (owned) (not nullable) */
|
||||
|
||||
GHashTable *info_by_gtype; /* GType -> GIBaseInfo */
|
||||
GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */
|
||||
GHashTable *interfaces_for_gtype; /* GType -> GTypeInterfaceCache */
|
||||
@ -187,10 +210,13 @@ gi_repository_init (GIRepository *repository)
|
||||
= g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify) g_free,
|
||||
(GDestroyNotify) gi_typelib_unref);
|
||||
repository->ordered_typelibs = g_ptr_array_new_with_free_func (NULL);
|
||||
repository->lazy_typelibs
|
||||
= g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify) g_free,
|
||||
(GDestroyNotify) gi_typelib_unref);
|
||||
repository->ordered_lazy_typelibs = g_ptr_array_new_with_free_func (NULL);
|
||||
|
||||
repository->info_by_gtype
|
||||
= g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
(GDestroyNotify) NULL,
|
||||
@ -212,7 +238,10 @@ gi_repository_finalize (GObject *object)
|
||||
GIRepository *repository = GI_REPOSITORY (object);
|
||||
|
||||
g_hash_table_destroy (repository->typelibs);
|
||||
g_ptr_array_unref (repository->ordered_typelibs);
|
||||
g_hash_table_destroy (repository->lazy_typelibs);
|
||||
g_ptr_array_unref (repository->ordered_lazy_typelibs);
|
||||
|
||||
g_hash_table_destroy (repository->info_by_gtype);
|
||||
g_hash_table_destroy (repository->info_by_error_domain);
|
||||
g_hash_table_destroy (repository->interfaces_for_gtype);
|
||||
@ -497,6 +526,29 @@ load_dependencies_recurse (GIRepository *repository,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Sort typelibs by namespace. The main requirement here is just to make iteration
|
||||
* deterministic, otherwise results can change as a lot of the code here would
|
||||
* just iterate over a `GHashTable`.
|
||||
*
|
||||
* A sub-requirement of this is that namespaces are sorted such that if a GType
|
||||
* or symbol is found in multiple namespaces where one is a prefix of the other,
|
||||
* the longest namespace wins. In practice, this only happens in
|
||||
* Gio/GioUnix/GioWin32, as all three of those namespaces refer to the same
|
||||
* `.so` file and overlapping sets of the same symbols, but we want the platform
|
||||
* specific namespace to be returned in preference to anything else (even though
|
||||
* either namespace is valid).
|
||||
* See https://gitlab.gnome.org/GNOME/glib/-/issues/3303 */
|
||||
static int
|
||||
sort_typelibs_cb (const void *a,
|
||||
const void *b)
|
||||
{
|
||||
GITypelib *typelib_a = *(GITypelib **) a;
|
||||
GITypelib *typelib_b = *(GITypelib **) b;
|
||||
|
||||
return strcmp (gi_typelib_get_namespace (typelib_a),
|
||||
gi_typelib_get_namespace (typelib_b));
|
||||
}
|
||||
|
||||
static const char *
|
||||
register_internal (GIRepository *repository,
|
||||
const char *source,
|
||||
@ -521,6 +573,8 @@ register_internal (GIRepository *repository,
|
||||
namespace));
|
||||
g_hash_table_insert (repository->lazy_typelibs,
|
||||
build_typelib_key (namespace, source), gi_typelib_ref (typelib));
|
||||
g_ptr_array_add (repository->ordered_lazy_typelibs, typelib);
|
||||
g_ptr_array_sort (repository->ordered_lazy_typelibs, sort_typelibs_cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -535,13 +589,20 @@ register_internal (GIRepository *repository,
|
||||
if (g_hash_table_lookup_extended (repository->lazy_typelibs,
|
||||
namespace,
|
||||
(gpointer)&key, &value))
|
||||
g_hash_table_remove (repository->lazy_typelibs, key);
|
||||
{
|
||||
g_hash_table_remove (repository->lazy_typelibs, key);
|
||||
g_ptr_array_remove (repository->ordered_lazy_typelibs, typelib);
|
||||
}
|
||||
else
|
||||
key = build_typelib_key (namespace, source);
|
||||
{
|
||||
key = build_typelib_key (namespace, source);
|
||||
}
|
||||
|
||||
g_hash_table_insert (repository->typelibs,
|
||||
g_steal_pointer (&key),
|
||||
gi_typelib_ref (typelib));
|
||||
g_ptr_array_add (repository->ordered_typelibs, typelib);
|
||||
g_ptr_array_sort (repository->ordered_typelibs, sort_typelibs_cb);
|
||||
}
|
||||
|
||||
/* These types might be resolved now, clear the cache */
|
||||
@ -870,32 +931,29 @@ gi_repository_get_info (GIRepository *repository,
|
||||
NULL, typelib, entry->offset);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *gtype_name;
|
||||
GITypelib *result_typelib;
|
||||
} FindByGTypeData;
|
||||
|
||||
static DirEntry *
|
||||
find_by_gtype (GHashTable *table, FindByGTypeData *data, gboolean check_prefix)
|
||||
find_by_gtype (GPtrArray *ordered_table,
|
||||
const char *gtype_name,
|
||||
gboolean check_prefix,
|
||||
GITypelib **out_result_typelib)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
DirEntry *ret;
|
||||
|
||||
g_hash_table_iter_init (&iter, table);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
/* Search in reverse order as the longest namespaces will be listed last, and
|
||||
* those are the ones we want to search first. */
|
||||
for (guint i = ordered_table->len; i > 0; i--)
|
||||
{
|
||||
GITypelib *typelib = (GITypelib*)value;
|
||||
GITypelib *typelib = g_ptr_array_index (ordered_table, i - 1);
|
||||
DirEntry *ret;
|
||||
|
||||
if (check_prefix)
|
||||
{
|
||||
if (!gi_typelib_matches_gtype_name_prefix (typelib, data->gtype_name))
|
||||
if (!gi_typelib_matches_gtype_name_prefix (typelib, gtype_name))
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = gi_typelib_get_dir_entry_by_gtype_name (typelib, data->gtype_name);
|
||||
ret = gi_typelib_get_dir_entry_by_gtype_name (typelib, gtype_name);
|
||||
if (ret)
|
||||
{
|
||||
data->result_typelib = typelib;
|
||||
*out_result_typelib = typelib;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -924,7 +982,8 @@ GIBaseInfo *
|
||||
gi_repository_find_by_gtype (GIRepository *repository,
|
||||
GType gtype)
|
||||
{
|
||||
FindByGTypeData data;
|
||||
const char *gtype_name;
|
||||
GITypelib *result_typelib = NULL;
|
||||
GIBaseInfo *cached;
|
||||
DirEntry *entry;
|
||||
|
||||
@ -940,8 +999,7 @@ gi_repository_find_by_gtype (GIRepository *repository,
|
||||
if (g_hash_table_contains (repository->unknown_gtypes, (gpointer)gtype))
|
||||
return NULL;
|
||||
|
||||
data.gtype_name = g_type_name (gtype);
|
||||
data.result_typelib = NULL;
|
||||
gtype_name = g_type_name (gtype);
|
||||
|
||||
/* Inside each typelib, we include the "C prefix" which acts as
|
||||
* a namespace mechanism. For GtkTreeView, the C prefix is Gtk.
|
||||
@ -950,25 +1008,25 @@ gi_repository_find_by_gtype (GIRepository *repository,
|
||||
* target type does not have this typelib's C prefix. Use this
|
||||
* assumption as our first attempt at locating the DirEntry.
|
||||
*/
|
||||
entry = find_by_gtype (repository->typelibs, &data, TRUE);
|
||||
entry = find_by_gtype (repository->ordered_typelibs, gtype_name, TRUE, &result_typelib);
|
||||
if (entry == NULL)
|
||||
entry = find_by_gtype (repository->lazy_typelibs, &data, TRUE);
|
||||
entry = find_by_gtype (repository->ordered_lazy_typelibs, gtype_name, TRUE, &result_typelib);
|
||||
|
||||
/* Not ever class library necessarily specifies a correct c_prefix,
|
||||
/* Not every class library necessarily specifies a correct c_prefix,
|
||||
* so take a second pass. This time we will try a global lookup,
|
||||
* ignoring prefixes.
|
||||
* See http://bugzilla.gnome.org/show_bug.cgi?id=564016
|
||||
*/
|
||||
if (entry == NULL)
|
||||
entry = find_by_gtype (repository->typelibs, &data, FALSE);
|
||||
entry = find_by_gtype (repository->ordered_typelibs, gtype_name, FALSE, &result_typelib);
|
||||
if (entry == NULL)
|
||||
entry = find_by_gtype (repository->lazy_typelibs, &data, FALSE);
|
||||
entry = find_by_gtype (repository->ordered_lazy_typelibs, gtype_name, FALSE, &result_typelib);
|
||||
|
||||
if (entry != NULL)
|
||||
{
|
||||
cached = gi_info_new_full (gi_typelib_blob_type_to_info_type (entry->blob_type),
|
||||
repository,
|
||||
NULL, data.result_typelib, entry->offset);
|
||||
NULL, result_typelib, entry->offset);
|
||||
|
||||
g_hash_table_insert (repository->info_by_gtype,
|
||||
(gpointer) gtype,
|
||||
@ -1020,28 +1078,27 @@ gi_repository_find_by_name (GIRepository *repository,
|
||||
NULL, typelib, entry->offset);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GIRepository *repository;
|
||||
GQuark domain;
|
||||
|
||||
GITypelib *result_typelib;
|
||||
DirEntry *result;
|
||||
} FindByErrorDomainData;
|
||||
|
||||
static void
|
||||
find_by_error_domain_foreach (gpointer key,
|
||||
gpointer value,
|
||||
gpointer datap)
|
||||
static DirEntry *
|
||||
find_by_error_domain (GPtrArray *ordered_typelibs,
|
||||
GQuark target_domain,
|
||||
GITypelib **out_typelib)
|
||||
{
|
||||
GITypelib *typelib = (GITypelib*)value;
|
||||
FindByErrorDomainData *data = datap;
|
||||
/* Search in reverse order as the longest namespaces will be listed last, and
|
||||
* those are the ones we want to search first. */
|
||||
for (guint i = ordered_typelibs->len; i > 0; i--)
|
||||
{
|
||||
GITypelib *typelib = g_ptr_array_index (ordered_typelibs, i - 1);
|
||||
DirEntry *entry;
|
||||
|
||||
if (data->result != NULL)
|
||||
return;
|
||||
entry = gi_typelib_get_dir_entry_by_error_domain (typelib, target_domain);
|
||||
if (entry != NULL)
|
||||
{
|
||||
*out_typelib = typelib;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
data->result = gi_typelib_get_dir_entry_by_error_domain (typelib, data->domain);
|
||||
if (data->result)
|
||||
data->result_typelib = typelib;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1064,8 +1121,9 @@ GIEnumInfo *
|
||||
gi_repository_find_by_error_domain (GIRepository *repository,
|
||||
GQuark domain)
|
||||
{
|
||||
FindByErrorDomainData data;
|
||||
GIEnumInfo *cached;
|
||||
DirEntry *result = NULL;
|
||||
GITypelib *result_typelib = NULL;
|
||||
|
||||
g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL);
|
||||
|
||||
@ -1075,20 +1133,15 @@ gi_repository_find_by_error_domain (GIRepository *repository,
|
||||
if (cached != NULL)
|
||||
return (GIEnumInfo *) gi_base_info_ref ((GIBaseInfo *)cached);
|
||||
|
||||
data.repository = repository;
|
||||
data.domain = domain;
|
||||
data.result_typelib = NULL;
|
||||
data.result = NULL;
|
||||
result = find_by_error_domain (repository->ordered_typelibs, domain, &result_typelib);
|
||||
if (result == NULL)
|
||||
result = find_by_error_domain (repository->ordered_lazy_typelibs, domain, &result_typelib);
|
||||
|
||||
g_hash_table_foreach (repository->typelibs, find_by_error_domain_foreach, &data);
|
||||
if (data.result == NULL)
|
||||
g_hash_table_foreach (repository->lazy_typelibs, find_by_error_domain_foreach, &data);
|
||||
|
||||
if (data.result != NULL)
|
||||
if (result != NULL)
|
||||
{
|
||||
cached = (GIEnumInfo *) gi_info_new_full (gi_typelib_blob_type_to_info_type (data.result->blob_type),
|
||||
cached = (GIEnumInfo *) gi_info_new_full (gi_typelib_blob_type_to_info_type (result->blob_type),
|
||||
repository,
|
||||
NULL, data.result_typelib, data.result->offset);
|
||||
NULL, result_typelib, result->offset);
|
||||
|
||||
g_hash_table_insert (repository->info_by_error_domain,
|
||||
GUINT_TO_POINTER (domain),
|
||||
@ -1179,13 +1232,16 @@ gi_repository_get_object_gtype_interfaces (GIRepository *repository,
|
||||
}
|
||||
|
||||
static void
|
||||
collect_namespaces (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
collect_namespaces (GPtrArray *ordered_typelibs,
|
||||
char **names,
|
||||
size_t *inout_i)
|
||||
{
|
||||
GList **list = data;
|
||||
|
||||
*list = g_list_append (*list, key);
|
||||
for (guint j = 0; j < ordered_typelibs->len; j++)
|
||||
{
|
||||
GITypelib *typelib = g_ptr_array_index (ordered_typelibs, j);
|
||||
const char *namespace = gi_typelib_get_namespace (typelib);
|
||||
names[(*inout_i)++] = g_strdup (namespace);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1207,20 +1263,18 @@ char **
|
||||
gi_repository_get_loaded_namespaces (GIRepository *repository,
|
||||
size_t *n_namespaces_out)
|
||||
{
|
||||
GList *l, *list = NULL;
|
||||
char **names;
|
||||
size_t i;
|
||||
size_t n_typelibs;
|
||||
|
||||
g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL);
|
||||
|
||||
g_hash_table_foreach (repository->typelibs, collect_namespaces, &list);
|
||||
g_hash_table_foreach (repository->lazy_typelibs, collect_namespaces, &list);
|
||||
|
||||
names = g_malloc0 (sizeof (char *) * (g_list_length (list) + 1));
|
||||
n_typelibs = repository->ordered_typelibs->len + repository->ordered_lazy_typelibs->len;
|
||||
names = g_malloc0 (sizeof (char *) * (n_typelibs + 1));
|
||||
i = 0;
|
||||
for (l = list; l; l = l->next)
|
||||
names[i++] = g_strdup (l->data);
|
||||
g_list_free (list);
|
||||
|
||||
collect_namespaces (repository->ordered_typelibs, names, &i);
|
||||
collect_namespaces (repository->ordered_lazy_typelibs, names, &i);
|
||||
|
||||
if (n_namespaces_out != NULL)
|
||||
*n_namespaces_out = i;
|
||||
|
@ -316,7 +316,8 @@ strsplit_iter_next (StrSplitIter *iter,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_overwrite_len (&iter->buf, 0, s, (gssize)len);
|
||||
g_string_overwrite_len (&iter->buf, 0, s, (gssize)len + 1);
|
||||
iter->buf.str[len] = '\0';
|
||||
*out_val = iter->buf.str;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -268,6 +268,7 @@ if host_system == 'windows'
|
||||
'--identifier-prefix=GWin32'
|
||||
],
|
||||
)
|
||||
gio_platform_gir = gio_win32_gir
|
||||
else
|
||||
gio_unix_gir_c_includes = []
|
||||
foreach h: gio_unix_include_headers
|
||||
@ -297,6 +298,7 @@ else
|
||||
'--identifier-prefix=GUnix'
|
||||
],
|
||||
)
|
||||
gio_platform_gir = gio_unix_gir
|
||||
endif
|
||||
|
||||
# GIRepository
|
||||
|
@ -29,6 +29,11 @@ if enable_gir
|
||||
gio_gir,
|
||||
]
|
||||
|
||||
gio_platform_gir_testing_dep = [
|
||||
gio_gir_testing_dep,
|
||||
gio_platform_gir,
|
||||
]
|
||||
|
||||
girepository_gir_testing_dep = [
|
||||
gio_gir_testing_dep,
|
||||
girepository_gir,
|
||||
@ -46,7 +51,8 @@ if enable_gir
|
||||
'depends': gobject_gir_testing_dep,
|
||||
},
|
||||
'repository' : {
|
||||
'depends': gio_gir_testing_dep,
|
||||
'depends': [gio_gir_testing_dep, gio_platform_gir_testing_dep],
|
||||
'dependencies': [libgio_dep],
|
||||
},
|
||||
'repository-search-paths' : {
|
||||
'c_args': '-DGOBJECT_INTROSPECTION_LIBDIR="@0@"'.format(glib_libdir),
|
||||
|
@ -35,6 +35,12 @@
|
||||
#include "glib.h"
|
||||
#include "test-common.h"
|
||||
|
||||
#if defined(G_OS_UNIX)
|
||||
#include "gio/gdesktopappinfo.h"
|
||||
#elif defined(G_OS_WIN32)
|
||||
#include "gio/gwin32inputstream.h"
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_repository_basic (RepositoryFixture *fx,
|
||||
const void *unused)
|
||||
@ -507,12 +513,31 @@ test_repository_error_quark (RepositoryFixture *fx,
|
||||
|
||||
g_test_summary ("Test finding an error quark by error domain");
|
||||
|
||||
/* Find a simple error domain. */
|
||||
error_info = gi_repository_find_by_error_domain (fx->repository, G_RESOLVER_ERROR);
|
||||
g_assert_nonnull (error_info);
|
||||
g_assert_true (GI_IS_ENUM_INFO (error_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (error_info)), ==, "ResolverError");
|
||||
|
||||
g_clear_pointer (&error_info, gi_base_info_unref);
|
||||
|
||||
/* Find again to check the caching. */
|
||||
error_info = gi_repository_find_by_error_domain (fx->repository, G_RESOLVER_ERROR);
|
||||
g_assert_nonnull (error_info);
|
||||
g_assert_true (GI_IS_ENUM_INFO (error_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (error_info)), ==, "ResolverError");
|
||||
|
||||
g_clear_pointer (&error_info, gi_base_info_unref);
|
||||
|
||||
/* Try and find an unknown error domain. */
|
||||
g_assert_null (gi_repository_find_by_error_domain (fx->repository, GI_REPOSITORY_ERROR));
|
||||
|
||||
/* And check caching for unknown error domains. */
|
||||
g_assert_null (gi_repository_find_by_error_domain (fx->repository, GI_REPOSITORY_ERROR));
|
||||
|
||||
/* It would be good to try and find one which will resolve in both Gio and
|
||||
* GioUnix/GioWin32, but neither of the platform-specific GIRs actually define
|
||||
* any error domains at the moment. */
|
||||
}
|
||||
|
||||
static void
|
||||
@ -777,6 +802,96 @@ test_repository_vfunc_info_with_invoker_on_object (RepositoryFixture *fx,
|
||||
g_clear_pointer (&invoker_info, gi_base_info_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
test_repository_find_by_gtype (RepositoryFixture *fx,
|
||||
const void *unused)
|
||||
{
|
||||
GIObjectInfo *object_info = NULL;
|
||||
|
||||
g_test_summary ("Test finding a GType");
|
||||
|
||||
object_info = (GIObjectInfo *) gi_repository_find_by_gtype (fx->repository, G_TYPE_OBJECT);
|
||||
g_assert_nonnull (object_info);
|
||||
g_assert_true (GI_IS_OBJECT_INFO (object_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (object_info)), ==, "Object");
|
||||
|
||||
g_clear_pointer (&object_info, gi_base_info_unref);
|
||||
|
||||
/* Find it again; this time it should hit the cache. */
|
||||
object_info = (GIObjectInfo *) gi_repository_find_by_gtype (fx->repository, G_TYPE_OBJECT);
|
||||
g_assert_nonnull (object_info);
|
||||
g_assert_true (GI_IS_OBJECT_INFO (object_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (object_info)), ==, "Object");
|
||||
|
||||
g_clear_pointer (&object_info, gi_base_info_unref);
|
||||
|
||||
/* Try and find an unknown GType. */
|
||||
g_assert_null (gi_repository_find_by_gtype (fx->repository, GI_TYPE_BASE_INFO));
|
||||
|
||||
/* And check caching for unknown GTypes. */
|
||||
g_assert_null (gi_repository_find_by_gtype (fx->repository, GI_TYPE_BASE_INFO));
|
||||
|
||||
/* Now try and find one which will resolve in both Gio and GioUnix/GioWin32.
|
||||
* The longest-named typelib should be returned. */
|
||||
{
|
||||
GType platform_specific_type;
|
||||
const char *expected_name, *expected_namespace;
|
||||
|
||||
#if defined(G_OS_UNIX)
|
||||
platform_specific_type = G_TYPE_DESKTOP_APP_INFO;
|
||||
expected_name = "DesktopAppInfo";
|
||||
expected_namespace = "GioUnix";
|
||||
#elif defined(G_OS_WIN32)
|
||||
platform_specific_type = G_TYPE_WIN32_INPUT_STREAM;
|
||||
expected_name = "InputStream";
|
||||
expected_namespace = "GioWin32";
|
||||
#else
|
||||
platform_specific_type = G_TYPE_INVALID;
|
||||
expected_name = NULL;
|
||||
expected_namespace = NULL;
|
||||
#endif
|
||||
|
||||
if (expected_name != NULL)
|
||||
{
|
||||
object_info = (GIObjectInfo *) gi_repository_find_by_gtype (fx->repository, platform_specific_type);
|
||||
g_assert_nonnull (object_info);
|
||||
g_assert_true (GI_IS_OBJECT_INFO (object_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (object_info)), ==, expected_name);
|
||||
g_assert_cmpstr (gi_base_info_get_namespace (GI_BASE_INFO (object_info)), ==, expected_namespace);
|
||||
g_clear_pointer (&object_info, gi_base_info_unref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_repository_loaded_namespaces (RepositoryFixture *fx,
|
||||
const void *unused)
|
||||
{
|
||||
char **namespaces;
|
||||
size_t n_namespaces;
|
||||
|
||||
/* These should be in alphabetical order */
|
||||
#if defined(G_OS_UNIX)
|
||||
const char *expected_namespaces[] = { "GLib", "GModule", "GObject", "Gio", "GioUnix", NULL };
|
||||
#elif defined(G_OS_WIN32)
|
||||
const char *expected_namespaces[] = { "GLib", "GModule", "GObject", "Gio", "GioWin32", NULL };
|
||||
#else
|
||||
const char *expected_namespaces[] = { "GLib", "GModule", "GObject", "Gio", NULL };
|
||||
#endif
|
||||
|
||||
g_test_summary ("Test listing loaded namespaces");
|
||||
|
||||
namespaces = gi_repository_get_loaded_namespaces (fx->repository, &n_namespaces);
|
||||
g_assert_cmpstrv (namespaces, expected_namespaces);
|
||||
g_assert_cmpuint (n_namespaces, ==, g_strv_length ((char **) expected_namespaces));
|
||||
g_strfreev (namespaces);
|
||||
|
||||
/* Test again but without passing `n_namespaces`. */
|
||||
namespaces = gi_repository_get_loaded_namespaces (fx->repository, NULL);
|
||||
g_assert_cmpstrv (namespaces, expected_namespaces);
|
||||
g_strfreev (namespaces);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -794,7 +909,7 @@ main (int argc,
|
||||
ADD_REPOSITORY_TEST ("/repository/constructor-return-type", test_repository_constructor_return_type, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/enum-info-c-identifier", test_repository_enum_info_c_identifier, &typelib_load_spec_glib);
|
||||
ADD_REPOSITORY_TEST ("/repository/enum-info-static-methods", test_repository_enum_info_static_methods, &typelib_load_spec_glib);
|
||||
ADD_REPOSITORY_TEST ("/repository/error-quark", test_repository_error_quark, &typelib_load_spec_gio);
|
||||
ADD_REPOSITORY_TEST ("/repository/error-quark", test_repository_error_quark, &typelib_load_spec_gio_platform);
|
||||
ADD_REPOSITORY_TEST ("/repository/flags-info-c-identifier", test_repository_flags_info_c_identifier, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/fundamental-ref-func", test_repository_fundamental_ref_func, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/instance-method-ownership-transfer", test_repository_instance_method_ownership_transfer, &typelib_load_spec_gio);
|
||||
@ -804,6 +919,8 @@ main (int argc,
|
||||
ADD_REPOSITORY_TEST ("/repository/vfunc-info-with-no-invoker", test_repository_vfunc_info_with_no_invoker, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/vfunc-info-with-invoker-on-interface", test_repository_vfunc_info_with_invoker_on_interface, &typelib_load_spec_gio);
|
||||
ADD_REPOSITORY_TEST ("/repository/vfunc-info-with-invoker-on-object", test_repository_vfunc_info_with_invoker_on_object, &typelib_load_spec_gio);
|
||||
ADD_REPOSITORY_TEST ("/repository/find-by-gtype", test_repository_find_by_gtype, &typelib_load_spec_gio_platform);
|
||||
ADD_REPOSITORY_TEST ("/repository/loaded-namespaces", test_repository_loaded_namespaces, &typelib_load_spec_gio_platform);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ typedef struct
|
||||
static const TypelibLoadSpec typelib_load_spec_glib = { "GLib", "2.0" };
|
||||
static const TypelibLoadSpec typelib_load_spec_gobject = { "GObject", "2.0" };
|
||||
static const TypelibLoadSpec typelib_load_spec_gio = { "Gio", "2.0" };
|
||||
#if defined(G_OS_UNIX)
|
||||
static const TypelibLoadSpec typelib_load_spec_gio_platform = { "GioUnix", "2.0" };
|
||||
#elif defined(G_OS_WIN32)
|
||||
static const TypelibLoadSpec typelib_load_spec_gio_platform = { "GioWin32", "2.0" };
|
||||
#endif
|
||||
|
||||
void repository_init (int *argc,
|
||||
char **argv[]);
|
||||
|
Loading…
Reference in New Issue
Block a user