gplugin/gplugin

A few updates to cleanup a bunch of code in libpurple.
feature/unload-failed-state
2020-04-10, Gary Kramlich
5a05c6354d62
Parents c4aa540655c4
Children 40d7a1490169
A few updates to cleanup a bunch of code in libpurple.

* Add a new plugin state UNLOAD_FAILED that tracks when a plugin failed to
unload.
* Add a new signal GPluginManager::unload-plugin-failed
* Update GPluginManager::load-failed to pass the error, if any, that the
plugin returned.
* Added gplugin_manager_foreach and GPluginManagerForeachFunc to make it
easier to operate on all plugins.
--- a/ChangeLog Sat Apr 11 10:52:48 2020 +0000
+++ b/ChangeLog Fri Apr 10 03:05:31 2020 -0500
@@ -9,6 +9,14 @@
* Removed GPluginVersionCompareFunc and the GPluginPluginInfo::version-func
property as they aren't necessary with semantic versioning. (Gary Kramlich)
* Fixed licenses throughout the codecase. (Richard Laager)
+ * Added new plugin state UNLOAD_FAILED. When a plugin fails to unload, it
+ now goes to UNLOAD_FAILED instead of LOADED. (Gary Kramlich)
+ * Added gplugin_manager_foreach and GPluginManagerForeachFunc to make it
+ easier to operate on all plugins. (Gary Kramlich)
+ * Added GPluginManager::unload-plugin-failed signal that gets emitted when
+ a plugin fails to unload.
+ * Made the GPluginManager::load-failed signal pass in the error, if any,
+ that the plugin returned. (Gary Kramlich)
Lua Loader
* Removed the moonscript support from the Lua loader. (Gary Kramlich)
--- a/gplugin/gplugin-loader-tests.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-loader-tests.c Fri Apr 10 03:05:31 2020 -0500
@@ -179,7 +179,7 @@
g_assert_cmpint(
gplugin_plugin_get_state(plugin),
==,
- GPLUGIN_PLUGIN_STATE_LOADED);
+ GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED);
g_object_unref(G_OBJECT(plugin));
}
--- a/gplugin/gplugin-manager.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-manager.c Fri Apr 10 03:05:31 2020 -0500
@@ -36,6 +36,15 @@
* loading, unloading, querying, checking for new plugins, and so on.
*/
+/**
+ * GPluginManagerForeachFunc:
+ * @id: The id of the plugin.
+ * @plugins: A #GSList of each plugin that has the id @id.
+ * @data: User data passed to gplugin_manager_foreach().
+ *
+ * A callback function for gplugin_manager_foreach().
+ */
+
/******************************************************************************
* Enums
*****************************************************************************/
@@ -45,6 +54,7 @@
SIG_LOAD_FAILED,
SIG_UNLOADING,
SIG_UNLOADED,
+ SIG_UNLOAD_FAILED,
N_SIGNALS,
};
@@ -83,7 +93,15 @@
void (*refresh)(GPluginManager *manager);
+ void (*foreach)(
+ GPluginManager *manager,
+ GPluginManagerForeachFunc func,
+ gpointer data);
+
GSList *(*find_plugins)(GPluginManager *manager, const gchar *id);
+ GSList *(*find_plugins_with_state)(
+ GPluginManager *manager,
+ GPluginPluginState state);
GList *(*list_plugins)(GPluginManager *manager);
@@ -107,13 +125,16 @@
GPluginPlugin *plugin,
GError **error);
void (*loaded_plugin)(GObject *manager, GPluginPlugin *plugin);
- void (*load_failed)(GObject *manager, GPluginPlugin *plugin);
+ void (*load_failed)(GObject *manager, GPluginPlugin *plugin, GError *error);
gboolean (*unloading_plugin)(
GObject *manager,
GPluginPlugin *plugin,
GError **error);
void (*unloaded_plugin)(GObject *manager, GPluginPlugin *plugin);
-
+ void (*unload_plugin_failed)(
+ GObject *manager,
+ GPluginPlugin *plugin,
+ GError *error);
} GPluginManagerClass;
#define GPLUGIN_TYPE_MANAGER (gplugin_manager_get_type())
@@ -683,6 +704,21 @@
gplugin_file_tree_free(root);
}
+static void
+gplugin_manager_real_foreach(
+ GPluginManager *manager,
+ GPluginManagerForeachFunc func,
+ gpointer data)
+{
+ GHashTableIter iter;
+ gpointer id = NULL, plugins = NULL;
+
+ g_hash_table_iter_init(&iter, manager->plugins);
+ while(g_hash_table_iter_next(&iter, &id, &plugins)) {
+ func((gchar *)id, (GSList *)plugins, data);
+ }
+}
+
static GSList *
gplugin_manager_real_find_plugins(GPluginManager *manager, const gchar *id)
{
@@ -696,6 +732,32 @@
return plugins_list;
}
+static GSList *
+gplugin_manager_real_find_plugins_with_state(
+ GPluginManager *manager,
+ GPluginPluginState state)
+{
+ GSList *plugins = NULL;
+ GHashTableIter iter;
+ gpointer value = NULL;
+
+ g_hash_table_iter_init(&iter, manager->plugins);
+ while(g_hash_table_iter_next(&iter, NULL, &value)) {
+ GSList *l = NULL;
+
+ for(l = (GSList *)value; l != NULL; l = l->next) {
+ GPluginPlugin *plugin = GPLUGIN_PLUGIN(l->data);
+
+ if(gplugin_plugin_get_state(plugin) == state) {
+ plugins =
+ g_slist_prepend(plugins, g_object_ref(G_OBJECT(plugin)));
+ }
+ }
+ }
+
+ return plugins;
+}
+
static GList *
gplugin_manager_real_list_plugins(GPluginManager *manager)
{
@@ -904,14 +966,20 @@
}
ret = gplugin_loader_load_plugin(loader, plugin, error);
- gplugin_plugin_set_state(
- plugin,
- (ret) ? GPLUGIN_PLUGIN_STATE_LOADED : GPLUGIN_PLUGIN_STATE_LOAD_FAILED);
+ if(ret) {
+ gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_LOADED);
+
+ g_signal_emit(manager, signals[SIG_LOADED], 0, plugin);
+ } else {
+ GError *real_error = NULL;
- if(ret)
- g_signal_emit(manager, signals[SIG_LOADED], 0, plugin);
- else
- g_signal_emit(manager, signals[SIG_LOAD_FAILED], 0, plugin);
+ if(error != NULL) {
+ real_error = *error;
+ }
+
+ gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_LOAD_FAILED);
+ g_signal_emit(manager, signals[SIG_LOAD_FAILED], 0, plugin, real_error);
+ }
return ret;
}
@@ -949,7 +1017,11 @@
if(ret) {
gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_QUERIED);
- g_signal_emit(manager, signals[SIG_UNLOADED], 0, plugin, error);
+ g_signal_emit(manager, signals[SIG_UNLOADED], 0, plugin);
+ } else {
+ gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED);
+
+ g_signal_emit(manager, signals[SIG_UNLOAD_FAILED], 0, plugin, error);
}
return ret;
@@ -1034,7 +1106,11 @@
manager_class->refresh = gplugin_manager_real_refresh;
+ manager_class->foreach = gplugin_manager_real_foreach;
+
manager_class->find_plugins = gplugin_manager_real_find_plugins;
+ manager_class->find_plugins_with_state =
+ gplugin_manager_real_find_plugins_with_state;
manager_class->list_plugins = gplugin_manager_real_list_plugins;
manager_class->get_plugin_dependencies =
@@ -1106,8 +1182,9 @@
NULL,
NULL,
G_TYPE_NONE,
- 1,
- G_TYPE_OBJECT);
+ 2,
+ G_TYPE_OBJECT,
+ G_TYPE_ERROR);
/**
* GPluginManager::unloading-plugin:
@@ -1136,7 +1213,7 @@
* @manager: the #gpluginpluginmanager instance. treat as a #gobject.
* @plugin: the #gpluginplugin that's about to be loaded.
*
- * emitted after a plugin is unloaded.
+ * emitted after a plugin is successfully unloaded.
*/
signals[SIG_UNLOADED] = g_signal_new(
"unloaded-plugin",
@@ -1149,6 +1226,28 @@
G_TYPE_NONE,
1,
G_TYPE_OBJECT);
+
+ /**
+ * GPluginManager::unload-plugin-failed:
+ * @manager: The #GPluginManager instance.
+ * @plugin: The #GPluginPlugin instance that failed to unload.
+ * @error: A #GError instance.
+ *
+ * Emitted when @manager was asked to unload @plugin, but @plugin returned
+ * %FALSE when it's unload function was called.
+ */
+ signals[SIG_UNLOAD_FAILED] = g_signal_new(
+ "unload-plugin-failed",
+ G_OBJECT_CLASS_TYPE(manager_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GPluginManagerClass, unload_plugin_failed),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_OBJECT,
+ G_TYPE_ERROR);
}
static void
@@ -1453,6 +1552,27 @@
}
/**
+ * gplugin_manager_foreach:
+ * @func: (scope call): The #GPluginManagerForeachFunc to call.
+ * @data: User data to pass to func.
+ *
+ * Calls @func for each plugin that is known.
+ */
+void
+gplugin_manager_foreach(GPluginManagerForeachFunc func, gpointer data)
+{
+ GPluginManager *manager = GPLUGIN_MANAGER_INSTANCE;
+ GPluginManagerClass *klass = NULL;
+
+ g_return_if_fail(GPLUGIN_IS_MANAGER(manager));
+ g_return_if_fail(func != NULL);
+
+ klass = GPLUGIN_MANAGER_GET_CLASS(manager);
+ if(klass && klass->foreach)
+ klass->foreach(manager, func, data);
+}
+
+/**
* gplugin_manager_find_plugins:
* @id: id string of the plugin to find.
*
@@ -1565,6 +1685,32 @@
}
/**
+ * gplugin_manager_find_plugins_with_state:
+ * @state: The #GPluginPluginState to look for.
+ *
+ * Finds all plugins that are currently have a state of @state.
+ *
+ * Returns: (element-type GPlugin.Plugin) (transfer full): A #GSList of
+ * referenced #GPluginPlugin's whose state is @state. Call
+ * g_slist_free_full() with a `DestroyNotify` of g_object_unref() on
+ * the returned value when you're done with it.
+ */
+GSList *
+gplugin_manager_find_plugins_with_state(GPluginPluginState state)
+{
+ GPluginManager *manager = GPLUGIN_MANAGER_INSTANCE;
+ GPluginManagerClass *klass = NULL;
+
+ g_return_val_if_fail(GPLUGIN_IS_MANAGER(manager), NULL);
+
+ klass = GPLUGIN_MANAGER_GET_CLASS(manager);
+ if(klass && klass->find_plugins_with_state)
+ return klass->find_plugins_with_state(manager, state);
+
+ return NULL;
+}
+
+/**
* gplugin_manager_find_plugin:
* @id: The id of the plugin to find.
*
--- a/gplugin/gplugin-manager.h Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-manager.h Fri Apr 10 03:05:31 2020 -0500
@@ -29,6 +29,11 @@
G_BEGIN_DECLS
+typedef void (*GPluginManagerForeachFunc)(
+ const gchar *id,
+ GSList *plugins,
+ gpointer data);
+
void gplugin_manager_append_path(const gchar *path);
void gplugin_manager_prepend_path(const gchar *path);
void gplugin_manager_remove_path(const gchar *path);
@@ -44,11 +49,14 @@
void gplugin_manager_refresh(void);
+void gplugin_manager_foreach(GPluginManagerForeachFunc func, gpointer data);
+
GSList *gplugin_manager_find_plugins(const gchar *id);
GSList *gplugin_manager_find_plugins_with_version(
const gchar *id,
const gchar *op,
const gchar *version);
+GSList *gplugin_manager_find_plugins_with_state(GPluginPluginState state);
GPluginPlugin *gplugin_manager_find_plugin(const gchar *id);
--- a/gplugin/gplugin-plugin.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-plugin.c Fri Apr 10 03:05:31 2020 -0500
@@ -38,6 +38,7 @@
* @GPLUGIN_PLUGIN_STATE_REQUERY: The plugin should be requeried.
* @GPLUGIN_PLUGIN_STATE_LOADED: The plugin is loaded.
* @GPLUGIN_PLUGIN_STATE_LOAD_FAILED: The plugin failed to load.
+ * @GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED: The plugin failed to unload.
*
* The known states of a plugin.
*/
--- a/gplugin/gplugin-plugin.h Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/gplugin-plugin.h Fri Apr 10 03:05:31 2020 -0500
@@ -33,6 +33,7 @@
GPLUGIN_PLUGIN_STATE_REQUERY,
GPLUGIN_PLUGIN_STATE_LOADED,
GPLUGIN_PLUGIN_STATE_LOAD_FAILED,
+ GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED,
/*< private >*/
GPLUGIN_PLUGIN_STATES, /*< skip >*/
--- a/gplugin/tests/meson.build Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/tests/meson.build Fri Apr 10 03:05:31 2020 -0500
@@ -28,6 +28,11 @@
dependencies : [gplugin_dep, GLIB, GOBJECT])
test('Core', e)
+e = executable('test-find-plugins', 'test-find-plugins.c',
+ c_args : ['-DTEST_DIR="@0@/plugins/"'.format(meson.current_build_dir())],
+ dependencies : [gplugin_dep, GLIB, GOBJECT])
+test('Find Plugins', e)
+
e = executable('test-loader-registration', 'test-loader-registration.c',
dependencies : [gplugin_dep, GLIB, GOBJECT])
test('Loader Registration', e)
--- a/gplugin/tests/test-core.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/tests/test-core.c Fri Apr 10 03:05:31 2020 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -119,7 +119,6 @@
gint
main(gint argc, gchar **argv)
{
-
g_test_init(&argc, &argv, NULL);
g_test_add_func("/core/init_uninit", test_gplugin_init_uninit);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gplugin/tests/test-find-plugins.c Fri Apr 10 03:05:31 2020 -0500
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
+ *
+ * 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 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <gplugin.h>
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+test_gplugin_manager_foreach_load_plugins(
+ G_GNUC_UNUSED const gchar *id,
+ GSList *plugins,
+ gpointer data)
+{
+ GSList *l = NULL;
+
+ for(l = plugins; l != NULL; l = l->next) {
+ gplugin_manager_load_plugin(GPLUGIN_PLUGIN(l->data), NULL);
+ }
+}
+
+static void
+test_gplugin_manager_foreach_unload_plugins(
+ G_GNUC_UNUSED const gchar *id,
+ GSList *plugins,
+ gpointer data)
+{
+ GSList *l = NULL;
+
+ for(l = plugins; l != NULL; l = l->next) {
+ gplugin_manager_unload_plugin(GPLUGIN_PLUGIN(l->data), NULL);
+ }
+}
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+/*< private >
+ * test_gplugin_manager_find_plugins_with_state:
+ *
+ * Runs through the normal plugins in the plugins directory, trying to progress
+ * their state each iteration while checking that
+ * gplugin_manager_find_plugins_with_state() returns the correct values.
+ *
+ * If any changes are made to the that plugins directory, this test will need
+ * to be updated.
+ */
+static void
+test_gplugin_manager_find_plugins_with_state(void)
+{
+ GSList *plugins = NULL;
+
+ /* this is the list of the current plugins and the furthest state they can
+ * make it in the plugin lifecycle:
+ *
+ * basic-plugin.c: unloaded
+ * broken-dependent-plugin.c: queried
+ * dependent-plugin.c: queried
+ * load-exception: load failed
+ * load-failed: load failed
+ * unload-failed: unload failed
+ */
+ gint QUERIED = 6;
+ gint LOADED = 2;
+ gint LOAD_FAILED = 2;
+ gint UNLOADED = 3; /* unloaded plugins go back to the queried state */
+ gint UNLOAD_FAILED = 1;
+
+ gplugin_init();
+
+ gplugin_manager_append_path(TEST_DIR);
+ gplugin_manager_refresh();
+
+ /* make sure that all the plugins are queried */
+ plugins =
+ gplugin_manager_find_plugins_with_state(GPLUGIN_PLUGIN_STATE_QUERIED);
+ g_assert_cmpint(g_slist_length(plugins), ==, QUERIED);
+ g_slist_free_full(plugins, g_object_unref);
+
+ /* now load all of the plugins */
+ gplugin_manager_foreach(test_gplugin_manager_foreach_load_plugins, NULL);
+
+ /* make sure we have the proper number loaded */
+ plugins =
+ gplugin_manager_find_plugins_with_state(GPLUGIN_PLUGIN_STATE_LOADED);
+ g_assert_cmpint(g_slist_length(plugins), ==, LOADED);
+ g_slist_free_full(plugins, g_object_unref);
+
+ /* make sure we have the proper number of load failed */
+ plugins = gplugin_manager_find_plugins_with_state(
+ GPLUGIN_PLUGIN_STATE_LOAD_FAILED);
+ g_assert_cmpint(g_slist_length(plugins), ==, LOAD_FAILED);
+ g_slist_free_full(plugins, g_object_unref);
+
+ /* unload all of the plugins */
+ gplugin_manager_foreach(test_gplugin_manager_foreach_unload_plugins, NULL);
+
+ /* make sure we have the proper number unloaded */
+ plugins =
+ gplugin_manager_find_plugins_with_state(GPLUGIN_PLUGIN_STATE_QUERIED);
+ g_assert_cmpint(g_slist_length(plugins), ==, UNLOADED);
+ g_slist_free_full(plugins, g_object_unref);
+
+ /* make sure we have the proper number of unload failed */
+ plugins = gplugin_manager_find_plugins_with_state(
+ GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED);
+ g_assert_cmpint(g_slist_length(plugins), ==, UNLOAD_FAILED);
+ g_slist_free_full(plugins, g_object_unref);
+
+ gplugin_uninit();
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func(
+ "/manager/find_plugins/with_state",
+ test_gplugin_manager_find_plugins_with_state);
+
+ return g_test_run();
+}
--- a/gplugin/tests/test-signals.c Sat Apr 11 10:52:48 2020 +0000
+++ b/gplugin/tests/test-signals.c Fri Apr 10 03:05:31 2020 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2014 Gary Kramlich <grim@reaperworld.com>
+ * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@
gboolean unloading;
gboolean unloaded;
gboolean load_failed;
+ gboolean unload_failed;
} TestGPluginManagerSignalsData;
/******************************************************************************
@@ -116,6 +117,7 @@
test_gplugin_manager_signals_load_failed(
G_GNUC_UNUSED GObject *manager,
G_GNUC_UNUSED GPluginPlugin *plugin,
+ G_GNUC_UNUSED GError *error,
gpointer d)
{
TestGPluginManagerSignalsData *data = (TestGPluginManagerSignalsData *)d;
@@ -123,6 +125,18 @@
data->load_failed = TRUE;
}
+static void
+test_gplugin_manager_signals_unload_failed(
+ G_GNUC_UNUSED GObject *manager,
+ G_GNUC_UNUSED GPluginPlugin *plugin,
+ G_GNUC_UNUSED GError *error,
+ gpointer d)
+{
+ TestGPluginManagerSignalsData *data = (TestGPluginManagerSignalsData *)d;
+
+ data->unload_failed = TRUE;
+}
+
/******************************************************************************
* Tests
*****************************************************************************/
@@ -132,7 +146,12 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
GError *error = NULL;
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
+ TestGPluginManagerSignalsData data = {
+ .loading = FALSE,
+ .loaded = FALSE,
+ .unloading = FALSE,
+ .unloaded = FALSE,
+ };
gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
@@ -182,7 +201,12 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
GError *error = NULL;
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
+ TestGPluginManagerSignalsData data = {
+ .loading = FALSE,
+ .loaded = FALSE,
+ .unloading = FALSE,
+ .unloaded = FALSE,
+ };
gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
@@ -229,7 +253,12 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
GError *error = NULL;
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
+ TestGPluginManagerSignalsData data = {
+ .loading = FALSE,
+ .loaded = FALSE,
+ .unloading = FALSE,
+ .unloaded = FALSE,
+ };
gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
@@ -279,8 +308,11 @@
GPluginPlugin *plugin = NULL;
GObject *manager = gplugin_manager_get_instance();
GError *error = NULL;
- TestGPluginManagerSignalsData data = {FALSE, FALSE, FALSE, FALSE, FALSE};
- gulong signals[] = {0, 0, 0, 0, 0};
+ TestGPluginManagerSignalsData data = {
+ .loading = FALSE,
+ .load_failed = FALSE,
+ };
+ gulong signals[] = {0, 0, 0, 0};
signals[0] = g_signal_connect(
manager,
@@ -306,13 +338,65 @@
g_signal_handler_disconnect(manager, signals[1]);
}
+static void
+test_gplugin_manager_signals_unload_failure(void)
+{
+ GPluginPlugin *plugin = NULL;
+ GObject *manager = gplugin_manager_get_instance();
+ GError *error = NULL;
+ TestGPluginManagerSignalsData data = {
+ .loading = FALSE,
+ .loaded = FALSE,
+ .unloading = FALSE,
+ .unload_failed = FALSE,
+ };
+ gulong signals[] = {0, 0, 0, 0};
+
+ signals[0] = g_signal_connect(
+ manager,
+ "loading-plugin",
+ G_CALLBACK(test_gplugin_manager_signals_normal_loading),
+ &data);
+ signals[1] = g_signal_connect(
+ manager,
+ "loaded-plugin",
+ G_CALLBACK(test_gplugin_manager_signals_normal_loaded),
+ &data);
+ signals[2] = g_signal_connect(
+ manager,
+ "unloading-plugin",
+ G_CALLBACK(test_gplugin_manager_signals_normal_unloading),
+ &data);
+ signals[3] = g_signal_connect(
+ manager,
+ "unload-plugin-failed",
+ G_CALLBACK(test_gplugin_manager_signals_unload_failed),
+ &data);
+
+ gplugin_manager_append_path(TEST_DIR);
+ gplugin_manager_refresh();
+
+ plugin = gplugin_manager_find_plugin("gplugin/native-unload-failed");
+ gplugin_manager_load_plugin(plugin, &error);
+ g_assert_no_error(error);
+ g_assert_true(data.loading);
+ g_assert_true(data.loaded);
+
+ gplugin_manager_unload_plugin(plugin, &error);
+ g_assert_error(error, GPLUGIN_DOMAIN, 0);
+ g_assert_true(data.unloading);
+ g_assert_true(data.unload_failed);
+
+ g_signal_handler_disconnect(manager, signals[0]);
+ g_signal_handler_disconnect(manager, signals[1]);
+}
+
/******************************************************************************
* Main
*****************************************************************************/
gint
main(gint argc, gchar **argv)
{
-
g_test_init(&argc, &argv, NULL);
gplugin_init();
@@ -329,6 +413,9 @@
g_test_add_func(
"/manager/signals/load-failed",
test_gplugin_manager_signals_load_failure);
+ g_test_add_func(
+ "/manager/signals/unload-failed",
+ test_gplugin_manager_signals_unload_failure);
return g_test_run();
}