diff --git a/gio/tests/defaultvalue.c b/gio/tests/defaultvalue.c index f99f98b28..bbc8b3ee2 100644 --- a/gio/tests/defaultvalue.c +++ b/gio/tests/defaultvalue.c @@ -17,9 +17,15 @@ * along with this library; if not, see . */ +#include "config.h" + #include #include +#ifdef HAVE_COCOA +#include +#endif + static void check_property (const char *output, GParamSpec *pspec, diff --git a/girepository/tests/function-info.c b/girepository/tests/function-info.c index 33cc2121e..9645cf46a 100644 --- a/girepository/tests/function-info.c +++ b/girepository/tests/function-info.c @@ -20,47 +20,22 @@ * Author: Philip Withnall */ -#include "glib.h" #include "girepository.h" #include "girffi.h" - -static GIRepository * -load_typelib_from_builddir (const char *name, - const char *version) -{ - GIRepository *repository; - char *gobject_typelib_dir = NULL; - GITypelib *typelib = NULL; - GError *local_error = NULL; - - gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); - g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); - gi_repository_prepend_search_path (gobject_typelib_dir); - g_free (gobject_typelib_dir); - - repository = gi_repository_new (); - g_assert_nonnull (repository); - - typelib = gi_repository_require (repository, name, version, 0, &local_error); - g_assert_no_error (local_error); - g_assert_nonnull (typelib); - - return g_steal_pointer (&repository); -} +#include "glib.h" +#include "test-common.h" static void -test_function_info_invoker (void) +test_function_info_invoker (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; GIFunctionInfo *function_info = NULL; GIFunctionInvoker invoker; GError *local_error = NULL; g_test_summary ("Test preparing a function invoker"); - repository = load_typelib_from_builddir ("GLib", "2.0"); - - function_info = (GIFunctionInfo *) gi_repository_find_by_name (repository, "GLib", "get_locale_variants"); + function_info = GI_FUNCTION_INFO (gi_repository_find_by_name (fx->repository, "GLib", "get_locale_variants")); g_assert_nonnull (function_info); gi_function_info_prep_invoker (function_info, &invoker, &local_error); @@ -68,21 +43,15 @@ test_function_info_invoker (void) gi_function_invoker_clear (&invoker); g_clear_pointer (&function_info, gi_base_info_unref); - - g_clear_object (&repository); } int main (int argc, char *argv[]) { - /* Isolate from the system typelibs and GIRs. */ - g_setenv ("GI_TYPELIB_PATH", "/dev/null", TRUE); - g_setenv ("GI_GIR_PATH", "/dev/null", TRUE); + repository_init (&argc, &argv); - g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); - - g_test_add_func ("/function-info/invoker", test_function_info_invoker); + ADD_REPOSITORY_TEST ("/function-info/invoker", test_function_info_invoker, &typelib_load_spec_glib); return g_test_run (); } diff --git a/girepository/tests/meson.build b/girepository/tests/meson.build index 237199094..0a2e27203 100644 --- a/girepository/tests/meson.build +++ b/girepository/tests/meson.build @@ -7,18 +7,25 @@ if enable_gir 'dependencies': [cmph_dep], }, 'function-info' : { + 'dependencies': [libffi_dep], 'depends': [glib_gir], }, 'gthash' : { 'dependencies': [girepo_gthash_dep], }, 'repository' : { - 'depends': [glib_gir, gobject_gir], + 'depends': [glib_gir, gio_gir, gobject_gir], }, 'repository-search-paths' : { 'c_args': '-DGOBJECT_INTROSPECTION_LIBDIR="@0@"'.format(glib_libdir), 'depends': [glib_gir], }, + 'struct-info' : { + 'depends': [gobject_gir], + }, + 'throws' : { + 'depends': [glib_gir, gio_gir], + }, } endif @@ -57,7 +64,7 @@ foreach test_name, extra_args : girepository_tests ) endif - exe = executable(test_name, source, + exe = executable(test_name, source, 'test-common.c', c_args: test_cargs + extra_args.get('c_args', []), cpp_args: test_cpp_args + extra_args.get('cpp_args', []), link_args: extra_args.get('link_args', []), diff --git a/girepository/tests/repository.c b/girepository/tests/repository.c index d1ac86541..beb84a5c0 100644 --- a/girepository/tests/repository.c +++ b/girepository/tests/repository.c @@ -1,4 +1,13 @@ /* + * Copyright 2008-2011 Colin Walters + * Copyright 2011 Laszlo Pandy + * Copyright 2011 Torsten Schönfeld + * Copyright 2011, 2012 Pavel Holejsovsky + * Copyright 2013 Martin Pitt + * Copyright 2014 Giovanni Campagna + * Copyright 2018 Christoph Reiter + * Copyright 2019, 2024 Philip Chimento + * Copyright 2022 Emmanuele Bassi * Copyright 2023 GNOME Foundation, Inc. * * SPDX-License-Identifier: LGPL-2.1-or-later @@ -19,62 +28,33 @@ * Author: Philip Withnall */ -#include "glib.h" +#include "config.h" + +#include "gio.h" #include "girepository.h" - -static GIRepository * -load_typelib_from_builddir (const char *name, - const char *version) -{ - GIRepository *repository; - char *gobject_typelib_dir = NULL; - GITypelib *typelib = NULL; - GError *local_error = NULL; - - gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); - g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); - gi_repository_prepend_search_path (gobject_typelib_dir); - g_free (gobject_typelib_dir); - - repository = gi_repository_new (); - g_assert_nonnull (repository); - - typelib = gi_repository_require (repository, name, version, 0, &local_error); - g_assert_no_error (local_error); - g_assert_nonnull (typelib); - - return g_steal_pointer (&repository); -} +#include "glib.h" +#include "test-common.h" static void -test_repository_basic (void) +test_repository_basic (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; - char *gobject_typelib_dir = NULL; const char * const * search_paths; - GITypelib *typelib = NULL; char **namespaces = NULL; const char *expected_namespaces[] = { "GLib", NULL }; - GError *local_error = NULL; char **versions; size_t n_versions; + const char *prefix = NULL; g_test_summary ("Test basic opening of a repository and requiring a typelib"); - gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); - g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); - gi_repository_prepend_search_path (gobject_typelib_dir); - - repository = gi_repository_new (); - g_assert_nonnull (repository); - - versions = gi_repository_enumerate_versions (repository, "SomeInvalidNamespace", &n_versions); + versions = gi_repository_enumerate_versions (fx->repository, "SomeInvalidNamespace", &n_versions); g_assert_nonnull (versions); g_assert_cmpstrv (versions, ((char *[]){NULL})); g_assert_cmpuint (n_versions, ==, 0); g_clear_pointer (&versions, g_strfreev); - versions = gi_repository_enumerate_versions (repository, "GLib", NULL); + versions = gi_repository_enumerate_versions (fx->repository, "GLib", NULL); g_assert_nonnull (versions); g_assert_cmpstrv (versions, ((char *[]){"2.0", NULL})); g_clear_pointer (&versions, g_strfreev); @@ -82,51 +62,44 @@ test_repository_basic (void) search_paths = gi_repository_get_search_path (NULL); g_assert_nonnull (search_paths); g_assert_cmpuint (g_strv_length ((char **) search_paths), >, 0); - g_assert_cmpstr (search_paths[0], ==, gobject_typelib_dir); + g_assert_cmpstr (search_paths[0], ==, fx->gobject_typelib_dir); - typelib = gi_repository_require (repository, "GLib", "2.0", 0, &local_error); - g_assert_no_error (local_error); - g_assert_nonnull (typelib); - - namespaces = gi_repository_get_loaded_namespaces (repository); + namespaces = gi_repository_get_loaded_namespaces (fx->repository); g_assert_cmpstrv (namespaces, expected_namespaces); g_strfreev (namespaces); - g_free (gobject_typelib_dir); - g_clear_object (&repository); + prefix = gi_repository_get_c_prefix (fx->repository, "GLib"); + g_assert_nonnull (prefix); + g_assert_cmpstr (prefix, ==, "G"); } static void -test_repository_info (void) +test_repository_info (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; - char *gobject_typelib_dir = NULL; - GITypelib *typelib = NULL; - GIObjectInfo *object_info = NULL; + GIBaseInfo *not_found_info = NULL; + GIObjectInfo *object_info = NULL, *object_info_by_gtype = NULL; GISignalInfo *signal_info = NULL; GIFunctionInfo *method_info = NULL; - GError *local_error = NULL; + GType gtype; g_test_summary ("Test retrieving some basic info blobs from a typelib"); - gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); - g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); - gi_repository_prepend_search_path (gobject_typelib_dir); - g_free (gobject_typelib_dir); + not_found_info = gi_repository_find_by_name (fx->repository, "GObject", "ThisDoesNotExist"); + g_assert_null (not_found_info); - repository = gi_repository_new (); - g_assert_nonnull (repository); - - typelib = gi_repository_require (repository, "GObject", "2.0", 0, &local_error); - g_assert_no_error (local_error); - g_assert_nonnull (typelib); - - object_info = (GIObjectInfo *) gi_repository_find_by_name (repository, "GObject", "Object"); + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Object")); g_assert_nonnull (object_info); - g_assert_cmpint (gi_base_info_get_info_type ((GIBaseInfo *) object_info), ==, GI_INFO_TYPE_OBJECT); - g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) object_info), ==, "Object"); - g_assert_cmpstr (gi_base_info_get_namespace ((GIBaseInfo *) object_info), ==, "GObject"); + g_assert_cmpint (gi_base_info_get_info_type (GI_BASE_INFO (object_info)), ==, GI_INFO_TYPE_OBJECT); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (object_info)), ==, "Object"); + g_assert_cmpstr (gi_base_info_get_namespace (GI_BASE_INFO (object_info)), ==, "GObject"); + + gtype = gi_registered_type_info_get_g_type (GI_REGISTERED_TYPE_INFO (object_info)); + g_assert_true (g_type_is_a (gtype, G_TYPE_OBJECT)); + + object_info_by_gtype = GI_OBJECT_INFO (gi_repository_find_by_gtype (fx->repository, G_TYPE_OBJECT)); + g_assert_nonnull (object_info); signal_info = gi_object_info_find_signal (object_info, "notify"); g_assert_nonnull (signal_info); @@ -138,57 +111,42 @@ test_repository_info (void) method_info = gi_object_info_find_method (object_info, "get_property"); g_assert_nonnull (method_info); - g_assert_true (gi_callable_info_is_method ((GICallableInfo *) method_info)); - g_assert_cmpuint (gi_callable_info_get_n_args ((GICallableInfo *) method_info), ==, 2); + g_assert_true (gi_callable_info_is_method (GI_CALLABLE_INFO (method_info))); + g_assert_cmpuint (gi_callable_info_get_n_args (GI_CALLABLE_INFO (method_info)), ==, 2); g_clear_pointer (&method_info, gi_base_info_unref); method_info = gi_object_info_get_method (object_info, gi_object_info_get_n_methods (object_info) - 1); - g_assert_true (gi_callable_info_is_method ((GICallableInfo *) method_info)); - g_assert_cmpuint (gi_callable_info_get_n_args ((GICallableInfo *) method_info), >, 0); + g_assert_true (gi_callable_info_is_method (GI_CALLABLE_INFO (method_info))); + g_assert_cmpuint (gi_callable_info_get_n_args (GI_CALLABLE_INFO (method_info)), >, 0); g_clear_pointer (&method_info, gi_base_info_unref); gi_base_info_unref (signal_info); gi_base_info_unref (object_info); - g_clear_object (&repository); + gi_base_info_unref (object_info_by_gtype); } static void -test_repository_dependencies (void) +test_repository_dependencies (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; - GITypelib *typelib; GError *error = NULL; - char *gobject_typelib_dir = NULL; char **dependencies; g_test_summary ("Test ensures namespace dependencies are correctly exposed"); - gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "gobject", NULL); - g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); - gi_repository_prepend_search_path (gobject_typelib_dir); - g_free (gobject_typelib_dir); - - repository = gi_repository_new (); - g_assert_nonnull (repository); - - typelib = gi_repository_require (repository, "GObject", "2.0", 0, &error); - g_assert_no_error (error); - g_assert_nonnull (typelib); - - dependencies = gi_repository_get_dependencies (repository, "GObject"); + dependencies = gi_repository_get_dependencies (fx->repository, "GObject"); g_assert_cmpuint (g_strv_length (dependencies), ==, 1); g_assert_true (g_strv_contains ((const char **) dependencies, "GLib-2.0")); g_clear_error (&error); - g_clear_object (&repository); g_clear_pointer (&dependencies, g_strfreev); } static void -test_repository_arg_info (void) +test_repository_arg_info (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; GIObjectInfo *object_info = NULL; GIStructInfo *struct_info = NULL; GIFunctionInfo *method_info = NULL; @@ -198,12 +156,10 @@ test_repository_arg_info (void) g_test_summary ("Test retrieving GIArgInfos from a typelib"); - repository = load_typelib_from_builddir ("GObject", "2.0"); - /* Test all the methods of GIArgInfo. Here we’re looking at the * `const char *property_name` argument of g_object_get_property(). (The * ‘self’ argument is not exposed through gi_callable_info_get_arg().) */ - object_info = (GIObjectInfo *) gi_repository_find_by_name (repository, "GObject", "Object"); + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Object")); g_assert_nonnull (object_info); method_info = gi_object_info_find_method (object_info, "get_property"); @@ -239,7 +195,7 @@ test_repository_arg_info (void) /* Test an (out) argument. Here it’s the `guint *n_properties` from * g_object_class_list_properties(). */ - struct_info = (GIStructInfo *) gi_repository_find_by_name (repository, "GObject", "ObjectClass"); + struct_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "ObjectClass")); g_assert_nonnull (struct_info); method_info = gi_struct_info_find_method (struct_info, "list_properties"); @@ -256,33 +212,27 @@ test_repository_arg_info (void) g_clear_pointer (&arg_info, gi_base_info_unref); g_clear_pointer (&method_info, gi_base_info_unref); g_clear_pointer (&struct_info, gi_base_info_unref); - - g_clear_object (&repository); } static void -test_repository_boxed_info (void) +test_repository_boxed_info (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; GIBoxedInfo *boxed_info = NULL; g_test_summary ("Test retrieving GIBoxedInfos from a typelib"); - repository = load_typelib_from_builddir ("GObject", "2.0"); - /* Test all the methods of GIBoxedInfo. This is simple, because there are none. */ - boxed_info = (GIBoxedInfo *) gi_repository_find_by_name (repository, "GObject", "BookmarkFile"); + boxed_info = GI_BOXED_INFO (gi_repository_find_by_name (fx->repository, "GObject", "BookmarkFile")); g_assert_nonnull (boxed_info); g_clear_pointer (&boxed_info, gi_base_info_unref); - - g_clear_object (&repository); } static void -test_repository_callable_info (void) +test_repository_callable_info (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; GIObjectInfo *object_info = NULL; GIFunctionInfo *method_info = NULL; GICallableInfo *callable_info; @@ -293,11 +243,9 @@ test_repository_callable_info (void) g_test_summary ("Test retrieving GICallableInfos from a typelib"); - repository = load_typelib_from_builddir ("GObject", "2.0"); - /* Test all the methods of GICallableInfo. Here we’re looking at * g_object_get_qdata(). */ - object_info = (GIObjectInfo *) gi_repository_find_by_name (repository, "GObject", "Object"); + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Object")); g_assert_nonnull (object_info); method_info = gi_object_info_find_method (object_info, "get_qdata"); @@ -333,46 +281,474 @@ test_repository_callable_info (void) g_clear_pointer (&method_info, gi_base_info_unref); g_clear_pointer (&object_info, gi_base_info_unref); - - g_clear_object (&repository); } static void -test_repository_callback_info (void) +test_repository_callback_info (RepositoryFixture *fx, + const void *unused) { - GIRepository *repository; GICallbackInfo *callback_info = NULL; g_test_summary ("Test retrieving GICallbackInfos from a typelib"); - repository = load_typelib_from_builddir ("GObject", "2.0"); - /* Test all the methods of GICallbackInfo. This is simple, because there are none. */ - callback_info = (GICallbackInfo *) gi_repository_find_by_name (repository, "GObject", "ObjectFinalizeFunc"); + callback_info = GI_CALLBACK_INFO (gi_repository_find_by_name (fx->repository, "GObject", "ObjectFinalizeFunc")); g_assert_nonnull (callback_info); g_clear_pointer (&callback_info, gi_base_info_unref); +} - g_clear_object (&repository); +static void +test_repository_char_types (RepositoryFixture *fx, + const void *unused) +{ + GIStructInfo *gvalue_info; + GIFunctionInfo *method_info; + GITypeInfo *type_info; + + g_test_summary ("Test that signed and unsigned char GITypeInfo have GITypeTag of INT8 and UINT8 respectively"); + + gvalue_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Value")); + g_assert_nonnull (gvalue_info); + + /* unsigned char */ + method_info = gi_struct_info_find_method (gvalue_info, "get_uchar"); + g_assert_nonnull (method_info); + + type_info = gi_callable_info_get_return_type (GI_CALLABLE_INFO (method_info)); + g_assert_nonnull (type_info); + g_assert_cmpuint (gi_type_info_get_tag (type_info), ==, GI_TYPE_TAG_UINT8); + + g_clear_pointer (&type_info, gi_base_info_unref); + g_clear_pointer (&method_info, gi_base_info_unref); + + /* signed char */ + method_info = gi_struct_info_find_method (gvalue_info, "get_schar"); + g_assert_nonnull (method_info); + + type_info = gi_callable_info_get_return_type (GI_CALLABLE_INFO (method_info)); + g_assert_nonnull (type_info); + g_assert_cmpuint (gi_type_info_get_tag (type_info), ==, GI_TYPE_TAG_INT8); + + g_clear_pointer (&type_info, gi_base_info_unref); + g_clear_pointer (&method_info, gi_base_info_unref); + g_clear_pointer (&gvalue_info, gi_base_info_unref); +} + +static void +test_repository_constructor_return_type (RepositoryFixture *fx, + const void *unused) +{ + GIObjectInfo *object_info = NULL; + GIFunctionInfo *constructor = NULL; + GITypeInfo *return_type = NULL; + GIBaseInfo *return_info = NULL; + const char *class_name = NULL; + const char *return_name = NULL; + + g_test_summary ("Test the return type of a constructor, g_object_newv()"); + + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Object")); + g_assert_nonnull (object_info); + + class_name = gi_registered_type_info_get_type_name (GI_REGISTERED_TYPE_INFO (object_info)); + g_assert_nonnull (class_name); + + constructor = gi_object_info_find_method (object_info, "newv"); + g_assert_nonnull (constructor); + + return_type = gi_callable_info_get_return_type (GI_CALLABLE_INFO (constructor)); + g_assert_nonnull (return_type); + g_assert_cmpuint (gi_type_info_get_tag (return_type), ==, GI_TYPE_TAG_INTERFACE); + + return_info = gi_type_info_get_interface (return_type); + g_assert_nonnull (return_info); + + return_name = gi_registered_type_info_get_type_name (GI_REGISTERED_TYPE_INFO (return_info)); + g_assert_nonnull (return_name); + g_assert_cmpstr (class_name, ==, return_name); + + g_clear_pointer (&return_info, gi_base_info_unref); + g_clear_pointer (&return_type, gi_base_info_unref); + g_clear_pointer (&constructor, gi_base_info_unref); + g_clear_pointer (&object_info, gi_base_info_unref); +} + +static void +test_repository_enum_info_c_identifier (RepositoryFixture *fx, + const void *unused) +{ + GIBaseInfo *info = NULL; + GIValueInfo *value_info = NULL; + unsigned n_infos, n_values, ix, jx; + const char *c_identifier = NULL; + + g_test_summary ("Test that every enum member has a C identifier"); + + n_infos = gi_repository_get_n_infos (fx->repository, "GLib"); + + for (ix = 0; ix < n_infos; ix++) + { + info = gi_repository_get_info (fx->repository, "GLib", ix); + + if (GI_IS_ENUM_INFO (info)) + { + n_values = gi_enum_info_get_n_values (GI_ENUM_INFO (info)); + for (jx = 0; jx < n_values; jx++) + { + value_info = gi_enum_info_get_value (GI_ENUM_INFO (info), jx); + c_identifier = gi_base_info_get_attribute (GI_BASE_INFO (value_info), "c:identifier"); + g_assert_nonnull (c_identifier); + + g_clear_pointer (&value_info, gi_base_info_unref); + } + } + + g_clear_pointer (&info, gi_base_info_unref); + } +} + +static void +test_repository_enum_info_static_methods (RepositoryFixture *fx, + const void *unused) +{ + GIEnumInfo *enum_info = NULL; + unsigned n_methods, ix; + GIFunctionInfo *function_info = NULL; + GIFunctionInfoFlags flags; + const char *symbol = NULL; + + g_test_summary ("Test an enum with methods"); + + enum_info = GI_ENUM_INFO (gi_repository_find_by_name (fx->repository, "GLib", "UnicodeScript")); + g_assert_nonnull (enum_info); + + n_methods = gi_enum_info_get_n_methods (enum_info); + g_assert_cmpuint (n_methods, >, 0); + + for (ix = 0; ix < n_methods; ix++) + { + function_info = gi_enum_info_get_method (enum_info, ix); + g_assert_nonnull (function_info); + + flags = gi_function_info_get_flags (function_info); + g_assert_false (flags & GI_FUNCTION_IS_METHOD); /* must be static */ + + symbol = gi_function_info_get_symbol (function_info); + g_assert_nonnull (symbol); + g_assert_true (g_str_has_prefix (symbol, "g_unicode_script_")); + + g_clear_pointer (&function_info, gi_base_info_unref); + } + + g_clear_pointer (&enum_info, gi_base_info_unref); +} + +static void +test_repository_error_quark (RepositoryFixture *fx, + const void *unused) +{ + GIEnumInfo *error_info = NULL; + + g_test_summary ("Test finding an error quark by 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); +} + +static void +test_repository_flags_info_c_identifier (RepositoryFixture *fx, + const void *unused) +{ + GIBaseInfo *info = NULL; + GIValueInfo *value_info = NULL; + unsigned n_infos, n_values, ix, jx; + const char *c_identifier = NULL; + + g_test_summary ("Test that every flags member has a C identifier"); + + n_infos = gi_repository_get_n_infos (fx->repository, "GLib"); + + for (ix = 0; ix < n_infos; ix++) + { + info = gi_repository_get_info (fx->repository, "GLib", ix); + + if (GI_IS_FLAGS_INFO (info)) + { + n_values = gi_enum_info_get_n_values (GI_ENUM_INFO (info)); + for (jx = 0; jx < n_values; jx++) + { + value_info = gi_enum_info_get_value (GI_ENUM_INFO (info), jx); + c_identifier = gi_base_info_get_attribute (GI_BASE_INFO (value_info), "c:identifier"); + g_assert_nonnull (c_identifier); + + g_clear_pointer (&value_info, gi_base_info_unref); + } + } + + g_clear_pointer (&info, gi_base_info_unref); + } +} + +static void +test_repository_fundamental_ref_func (RepositoryFixture *fx, + const void *unused) +{ + GIObjectInfo *info; + + g_test_summary ("Test getting the ref func of a fundamental type"); + + info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "ParamSpec")); + g_assert_nonnull (info); + + g_assert_nonnull (gi_object_info_get_ref_function_pointer (info)); + + g_clear_pointer (&info, gi_base_info_unref); +} + +static void +test_repository_instance_method_ownership_transfer (RepositoryFixture *fx, + const void *unused) +{ + GIObjectInfo *class_info = NULL; + GIFunctionInfo *func_info = NULL; + GITransfer transfer; + + g_test_summary ("Test two methods of the same object having opposite ownership transfer of the instance parameter"); + + class_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "Gio", "DBusMethodInvocation")); + g_assert_nonnull (class_info); + + func_info = gi_object_info_find_method (class_info, "get_connection"); + g_assert_nonnull (func_info); + transfer = gi_callable_info_get_instance_ownership_transfer (GI_CALLABLE_INFO (func_info)); + g_assert_cmpint (GI_TRANSFER_NOTHING, ==, transfer); + + g_clear_pointer (&func_info, gi_base_info_unref); + + func_info = gi_object_info_find_method (class_info, "return_error_literal"); + g_assert_nonnull (func_info); + transfer = gi_callable_info_get_instance_ownership_transfer (GI_CALLABLE_INFO (func_info)); + g_assert_cmpint (GI_TRANSFER_EVERYTHING, ==, transfer); + + g_clear_pointer (&func_info, gi_base_info_unref); + g_clear_pointer (&class_info, gi_base_info_unref); +} + +static void +test_repository_object_gtype_interfaces (RepositoryFixture *fx, + const void *unused) +{ + GIInterfaceInfo **interfaces; + size_t n_interfaces, ix; + const char *name; + gboolean found_initable = FALSE, found_async_initable = FALSE; + + g_test_summary ("Test gi_repository_get_object_gtype_interfaces()"); + + gi_repository_get_object_gtype_interfaces (fx->repository, G_TYPE_DBUS_CONNECTION, &n_interfaces, &interfaces); + + g_assert_cmpuint (n_interfaces, ==, 2); + + for (ix = 0; ix < n_interfaces; ix++) + { + name = gi_base_info_get_name (GI_BASE_INFO (*(interfaces + ix))); + if (strcmp (name, "Initable") == 0) + found_initable = TRUE; + else if (strcmp (name, "AsyncInitable") == 0) + found_async_initable = TRUE; + } + + g_assert_true (found_initable); + g_assert_true (found_async_initable); +} + +static void +test_repository_signal_info_with_array_length_arg (RepositoryFixture *fx, + const void *unused) +{ + GIObjectInfo *gsettings_info = NULL; + GISignalInfo *sig_info = NULL; + GIArgInfo *arg_info = NULL; + GITypeInfo *type_info = NULL; + unsigned length_ix; + + g_test_summary ("Test finding the associated array length argument of an array parameter of a signal"); + + gsettings_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "Gio", "Settings")); + g_assert_nonnull (gsettings_info); + + sig_info = gi_object_info_find_signal (gsettings_info, "change-event"); + g_assert_nonnull (sig_info); + + g_assert_cmpuint (gi_callable_info_get_n_args (GI_CALLABLE_INFO (sig_info)), ==, 2); + + /* verify array argument */ + arg_info = gi_callable_info_get_arg (GI_CALLABLE_INFO (sig_info), 0); + g_assert_nonnull (arg_info); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (arg_info)), ==, "keys"); + + type_info = gi_arg_info_get_type_info (arg_info); + g_assert_nonnull (type_info); + g_assert_cmpint (gi_type_info_get_tag (type_info), ==, GI_TYPE_TAG_ARRAY); + g_assert_cmpint (gi_type_info_get_array_type (type_info), ==, GI_ARRAY_TYPE_C); + g_assert_false (gi_type_info_is_zero_terminated (type_info)); + gboolean ok = gi_type_info_get_array_length_index (type_info, &length_ix); + g_assert_true (ok); + g_assert_cmpuint (length_ix, ==, 1); + + g_clear_pointer (&arg_info, gi_base_info_unref); + g_clear_pointer (&type_info, gi_base_info_unref); + + /* verify array length argument */ + arg_info = gi_callable_info_get_arg (GI_CALLABLE_INFO (sig_info), 1); + g_assert_nonnull (arg_info); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (arg_info)), ==, "n_keys"); + + g_clear_pointer (&arg_info, gi_base_info_unref); + g_clear_pointer (&type_info, gi_base_info_unref); + g_clear_pointer (&sig_info, gi_base_info_unref); + g_clear_pointer (&gsettings_info, gi_base_info_unref); +} + +static void +test_repository_type_info_name (RepositoryFixture *fx, + const void *unused) +{ + GIInterfaceInfo *interface_info = NULL; + GIVFuncInfo *vfunc; + GITypeInfo *typeinfo; + + g_test_summary ("Test that gi_base_info_get_name() returns null for GITypeInfo"); + g_test_bug ("https://gitlab.gnome.org/GNOME/gobject-introspection/issues/96"); + + interface_info = GI_INTERFACE_INFO (gi_repository_find_by_name (fx->repository, "Gio", "File")); + g_assert_nonnull (interface_info); + vfunc = gi_interface_info_find_vfunc (interface_info, "read_async"); + g_assert_nonnull (vfunc); + + typeinfo = gi_callable_info_get_return_type (GI_CALLABLE_INFO (vfunc)); + g_assert_nonnull (typeinfo); + + g_assert_null (gi_base_info_get_name (GI_BASE_INFO (typeinfo))); + + g_clear_pointer (&interface_info, gi_base_info_unref); + g_clear_pointer (&vfunc, gi_base_info_unref); + g_clear_pointer (&typeinfo, gi_base_info_unref); +} + +static void +test_repository_vfunc_info_with_no_invoker (RepositoryFixture *fx, + const void *unused) +{ + GIObjectInfo *object_info = NULL; + GIVFuncInfo *vfunc_info = NULL; + GIFunctionInfo *invoker_info = NULL; + + g_test_summary ("Test vfunc with no known invoker on object, such as GObject.dispose"); + + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Object")); + g_assert_nonnull (object_info); + + vfunc_info = gi_object_info_find_vfunc (object_info, "dispose"); + g_assert_nonnull (vfunc_info); + + invoker_info = gi_vfunc_info_get_invoker (vfunc_info); + g_assert_null (invoker_info); + + g_clear_pointer (&object_info, gi_base_info_unref); + g_clear_pointer (&vfunc_info, gi_base_info_unref); +} + +static void +test_repository_vfunc_info_with_invoker_on_interface (RepositoryFixture *fx, + const void *unused) +{ + GIInterfaceInfo *interface_info = NULL; + GIVFuncInfo *vfunc_info = NULL; + GIFunctionInfo *invoker_info = NULL; + + g_test_summary ("Test vfunc with invoker on interface, such as GFile.read_async"); + + interface_info = GI_INTERFACE_INFO (gi_repository_find_by_name (fx->repository, "Gio", "File")); + g_assert_nonnull (interface_info); + + vfunc_info = gi_interface_info_find_vfunc (interface_info, "read_async"); + g_assert_nonnull (vfunc_info); + + invoker_info = gi_vfunc_info_get_invoker (vfunc_info); + g_assert_nonnull (invoker_info); + + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (invoker_info)), ==, "read_async"); + + g_clear_pointer (&interface_info, gi_base_info_unref); + g_clear_pointer (&vfunc_info, gi_base_info_unref); + g_clear_pointer (&invoker_info, gi_base_info_unref); +} + +static void +test_repository_vfunc_info_with_invoker_on_object (RepositoryFixture *fx, + const void *unused) +{ + GIObjectInfo *object_info = NULL; + GIVFuncInfo *vfunc_info = NULL; + GIFunctionInfo *invoker_info = NULL; + + g_test_summary ("Test vfunc with invoker on object, such as GAppLaunchContext.get_display"); + + object_info = GI_OBJECT_INFO (gi_repository_find_by_name (fx->repository, "Gio", "AppLaunchContext")); + g_assert_nonnull (object_info); + + vfunc_info = gi_object_info_find_vfunc (object_info, "get_display"); + g_assert_nonnull (vfunc_info); + + invoker_info = gi_vfunc_info_get_invoker (vfunc_info); + g_assert_nonnull (invoker_info); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (invoker_info)), ==, "get_display"); + + /* And let's be sure we can find the method directly */ + g_clear_pointer (&invoker_info, gi_base_info_unref); + + invoker_info = gi_object_info_find_method (object_info, "get_display"); + g_assert_nonnull (invoker_info); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (invoker_info)), ==, "get_display"); + + g_clear_pointer (&object_info, gi_base_info_unref); + g_clear_pointer (&vfunc_info, gi_base_info_unref); + g_clear_pointer (&invoker_info, gi_base_info_unref); } int main (int argc, char *argv[]) { - /* Isolate from the system typelibs and GIRs. */ - g_setenv ("GI_TYPELIB_PATH", "/dev/null", TRUE); - g_setenv ("GI_GIR_PATH", "/dev/null", TRUE); + repository_init (&argc, &argv); - g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); - - g_test_add_func ("/repository/basic", test_repository_basic); - g_test_add_func ("/repository/info", test_repository_info); - g_test_add_func ("/repository/dependencies", test_repository_dependencies); - g_test_add_func ("/repository/arg-info", test_repository_arg_info); - g_test_add_func ("/repository/boxed-info", test_repository_boxed_info); - g_test_add_func ("/repository/callable-info", test_repository_callable_info); - g_test_add_func ("/repository/callback-info", test_repository_callback_info); + ADD_REPOSITORY_TEST ("/repository/basic", test_repository_basic, &typelib_load_spec_glib); + ADD_REPOSITORY_TEST ("/repository/info", test_repository_info, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/dependencies", test_repository_dependencies, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/arg-info", test_repository_arg_info, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/boxed-info", test_repository_boxed_info, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/callable-info", test_repository_callable_info, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/callback-info", test_repository_callback_info, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/repository/char-types", test_repository_char_types, &typelib_load_spec_gobject); + 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/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); + ADD_REPOSITORY_TEST ("/repository/object-gtype-interfaces", test_repository_object_gtype_interfaces, &typelib_load_spec_gio); + ADD_REPOSITORY_TEST ("/repository/signal-info-with-array-length-arg", test_repository_signal_info_with_array_length_arg, &typelib_load_spec_gio); + ADD_REPOSITORY_TEST ("/repository/type-info-name", test_repository_type_info_name, &typelib_load_spec_gio); + 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); return g_test_run (); } diff --git a/girepository/tests/struct-info.c b/girepository/tests/struct-info.c new file mode 100644 index 000000000..5a06fc060 --- /dev/null +++ b/girepository/tests/struct-info.c @@ -0,0 +1,120 @@ +/* + * Copyright 2014 Simon Feltman + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "girepository.h" +#include "test-common.h" + +static void +test_field_iterators (RepositoryFixture *fx, + const void *unused) +{ + GIStructInfo *class_info = NULL; + GIFieldInfo *field_info = NULL; + unsigned ix; + + g_test_summary ("Test iterating through a struct's fields with gi_struct_info_get_field()"); + + class_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "ObjectClass")); + g_assert_nonnull (class_info); + + for (ix = 0; ix < gi_struct_info_get_n_fields (class_info); ix++) + { + const char *field_name = NULL; + GIFieldInfo *found = NULL; + + field_info = gi_struct_info_get_field (class_info, ix); + g_assert_nonnull (field_info); + + field_name = gi_base_info_get_name (GI_BASE_INFO (field_info)); + g_assert_nonnull (field_name); + + found = gi_struct_info_find_field (class_info, field_name); + g_assert_nonnull (found); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (found)), ==, field_name); + + g_clear_pointer (&found, gi_base_info_unref); + g_clear_pointer (&field_info, gi_base_info_unref); + } + + field_info = gi_struct_info_find_field (class_info, "not_a_real_field_name"); + g_assert_null (field_info); + + g_clear_pointer (&class_info, gi_base_info_unref); +} + +static void +test_size_of_gvalue (RepositoryFixture *fx, + const void *unused) +{ + GIStructInfo *struct_info; + + g_test_summary ("Test that gi_struct_info_get_size() reports the correct sizeof GValue"); + + struct_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GObject", "Value")); + g_assert_nonnull (struct_info); + + g_assert_cmpuint (gi_struct_info_get_size (struct_info), ==, sizeof (GValue)); + + g_clear_pointer (&struct_info, gi_base_info_unref); +} + +static void +test_is_pointer_for_struct_method_arg (RepositoryFixture *fx, + const void *unused) +{ + GIStructInfo *variant_info = NULL; + GIFunctionInfo *equal_info = NULL; + GIArgInfo *arg_info = NULL; + GITypeInfo *type_info = NULL; + + g_test_summary ("Test that a struct method reports the correct type with gi_type_info_is_pointer()"); + + variant_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "GLib", "Variant")); + g_assert_nonnull (variant_info); + + equal_info = gi_struct_info_find_method (variant_info, "equal"); + g_assert_nonnull (equal_info); + + arg_info = gi_callable_info_get_arg (GI_CALLABLE_INFO (equal_info), 0); + g_assert_nonnull (arg_info); + + type_info = gi_arg_info_get_type_info (arg_info); + g_assert_nonnull (type_info); + g_assert_true (gi_type_info_is_pointer (type_info)); + + g_clear_pointer (&type_info, gi_base_info_unref); + g_clear_pointer (&arg_info, gi_base_info_unref); + g_clear_pointer (&equal_info, gi_base_info_unref); + g_clear_pointer (&variant_info, gi_base_info_unref); +} + +int +main (int argc, + char *argv[]) +{ + repository_init (&argc, &argv); + + ADD_REPOSITORY_TEST ("/struct-info/field-iterators", test_field_iterators, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/struct-info/sizeof-gvalue", test_size_of_gvalue, &typelib_load_spec_gobject); + ADD_REPOSITORY_TEST ("/struct-info/is-pointer-for-struct-method-arg", test_is_pointer_for_struct_method_arg, &typelib_load_spec_glib); + + return g_test_run (); +} diff --git a/girepository/tests/test-common.c b/girepository/tests/test-common.c new file mode 100644 index 000000000..b6edc07f8 --- /dev/null +++ b/girepository/tests/test-common.c @@ -0,0 +1,67 @@ +/* + * Copyright 2023 GNOME Foundation, Inc. + * Copyright 2024 Philip Chimento + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "girepository.h" +#include "glib.h" +#include "test-common.h" + +void +repository_init (int *argc, + char **argv[]) +{ + /* Isolate from the system typelibs and GIRs. */ + g_setenv ("GI_TYPELIB_PATH", "/dev/null", TRUE); + g_setenv ("GI_GIR_PATH", "/dev/null", TRUE); + + g_test_init (argc, argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); +} + +void +repository_setup (RepositoryFixture *fx, + const void *data) +{ + GITypelib *typelib = NULL; + GError *local_error = NULL; + TypelibLoadSpec *load_spec = (TypelibLoadSpec *) data; + + fx->gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); + g_test_message ("Using GI_TYPELIB_DIR = %s", fx->gobject_typelib_dir); + gi_repository_prepend_search_path (fx->gobject_typelib_dir); + + fx->repository = gi_repository_new (); + g_assert_nonnull (fx->repository); + + if (load_spec) + { + typelib = gi_repository_require (fx->repository, load_spec->name, load_spec->version, 0, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (typelib); + } +} + +void +repository_teardown (RepositoryFixture *fx, + const void *unused) +{ + g_clear_pointer (&fx->gobject_typelib_dir, g_free); + g_clear_object (&fx->repository); +} diff --git a/girepository/tests/test-common.h b/girepository/tests/test-common.h new file mode 100644 index 000000000..8793a635d --- /dev/null +++ b/girepository/tests/test-common.h @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Philip Chimento + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include "config.h" + +#include "girepository.h" + +typedef struct +{ + GIRepository *repository; + char *gobject_typelib_dir; +} RepositoryFixture; + +typedef struct +{ + const char *name; + const char *version; +} TypelibLoadSpec; + +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" }; + +void repository_init (int *argc, + char **argv[]); + +void repository_setup (RepositoryFixture *fx, + const void *data); + +void repository_teardown (RepositoryFixture *fx, + const void *unused); + +#define ADD_REPOSITORY_TEST(testpath, ftest, load_spec) \ + g_test_add ((testpath), RepositoryFixture, load_spec, repository_setup, (ftest), repository_teardown) diff --git a/girepository/tests/throws.c b/girepository/tests/throws.c new file mode 100644 index 000000000..170c92ebd --- /dev/null +++ b/girepository/tests/throws.c @@ -0,0 +1,126 @@ +/* + * Copyright 2008 litl, LLC + * Copyright 2014 Simon Feltman + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "girepository.h" +#include "test-common.h" + +static void +test_invoke_gerror (RepositoryFixture *fx, + const void *unused) +{ + GIFunctionInfo *func_info = NULL; + GIArgument in_arg[1]; + GIArgument ret_arg; + GError *error = NULL; + gboolean invoke_return; + + g_test_summary ("Test invoking a function that throws a GError"); + + func_info = GI_FUNCTION_INFO (gi_repository_find_by_name (fx->repository, "GLib", "file_read_link")); + g_assert_nonnull (func_info); + g_assert_true (gi_function_info_get_flags (func_info) & GI_FUNCTION_THROWS); + g_assert_true (gi_callable_info_can_throw_gerror (GI_CALLABLE_INFO (func_info))); + + in_arg[0].v_string = g_strdup ("non-existent-file/hope"); + invoke_return = gi_function_info_invoke (func_info, in_arg, 1, NULL, 0, &ret_arg, &error); + g_clear_pointer (&in_arg[0].v_string, g_free); + + g_assert_false (invoke_return); + g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT); + + g_clear_error (&error); + g_clear_pointer (&func_info, gi_base_info_unref); +} + +static void +test_vfunc_can_throw_gerror (RepositoryFixture *fx, + const void *unused) +{ + GIInterfaceInfo *interface_info = NULL; + GIFunctionInfo *invoker_info = NULL; + GIVFuncInfo *vfunc_info = NULL; + + g_test_summary ("Test gi_callable_info_can_throw_gerror() on a vfunc"); + + interface_info = GI_INTERFACE_INFO (gi_repository_find_by_name (fx->repository, "Gio", "AppInfo")); + g_assert_nonnull (interface_info); + + invoker_info = gi_interface_info_find_method (interface_info, "launch"); + g_assert_nonnull (invoker_info); + g_assert_true (gi_function_info_get_flags (invoker_info) & GI_FUNCTION_THROWS); + g_assert_true (gi_callable_info_can_throw_gerror (GI_CALLABLE_INFO (invoker_info))); + + vfunc_info = gi_interface_info_find_vfunc (interface_info, "launch"); + g_assert_nonnull (vfunc_info); + g_assert_true (gi_vfunc_info_get_flags (vfunc_info) & GI_VFUNC_THROWS); + g_assert_true (gi_callable_info_can_throw_gerror (GI_CALLABLE_INFO (vfunc_info))); + + g_clear_pointer (&vfunc_info, gi_base_info_unref); + g_clear_pointer (&invoker_info, gi_base_info_unref); + g_clear_pointer (&interface_info, gi_base_info_unref); +} + +static void +test_callback_can_throw_gerror (RepositoryFixture *fx, + const void *unused) +{ + GIStructInfo *class_info = NULL; + GIFieldInfo *field_info = NULL; + GITypeInfo *field_type = NULL; + GICallbackInfo *callback_info = NULL; + + g_test_summary ("Test gi_callable_info_can_throw_gerror() on a callback"); + + class_info = GI_STRUCT_INFO (gi_repository_find_by_name (fx->repository, "Gio", "AppInfoIface")); + g_assert_nonnull (class_info); + + field_info = gi_struct_info_find_field (class_info, "launch"); + g_assert_nonnull (field_info); + g_assert_true (GI_IS_FIELD_INFO (field_info)); + + field_type = gi_field_info_get_type_info (field_info); + g_assert_nonnull (field_type); + g_assert_true (GI_IS_TYPE_INFO (field_type)); + g_assert_cmpint (gi_type_info_get_tag (field_type), ==, GI_TYPE_TAG_INTERFACE); + + callback_info = GI_CALLBACK_INFO (gi_type_info_get_interface (field_type)); + g_assert_nonnull (callback_info); + g_assert (gi_callable_info_can_throw_gerror (GI_CALLABLE_INFO (callback_info))); + + g_clear_pointer (&callback_info, gi_base_info_unref); + g_clear_pointer (&field_type, gi_base_info_unref); + g_clear_pointer (&field_info, gi_base_info_unref); + g_clear_pointer (&class_info, gi_base_info_unref); +} + +int +main (int argc, + char *argv[]) +{ + repository_init (&argc, &argv); + + ADD_REPOSITORY_TEST ("/throws/invoke-gerror", test_invoke_gerror, &typelib_load_spec_glib); + ADD_REPOSITORY_TEST ("/throws/vfunc-can-throw-gerror", test_vfunc_can_throw_gerror, &typelib_load_spec_gio); + ADD_REPOSITORY_TEST ("/throws/callback-can-throw-gerror", test_callback_can_throw_gerror, &typelib_load_spec_gio); + + return g_test_run (); +}