[gnome-builder/wip/chergert/unittests] testing: start on unit testing
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/unittests] testing: start on unit testing
- Date: Thu, 19 Oct 2017 09:40:36 +0000 (UTC)
commit 00e5fdc71e98dda20bb47487936bd51a8a3b5c94
Author: Christian Hergert <chergert redhat com>
Date: Fri Oct 13 17:40:19 2017 -0700
testing: start on unit testing
src/libide/ide-context.c | 50 +++-
src/libide/ide-context.h | 1 +
src/libide/ide-types.h | 4 +
src/libide/ide.h | 2 +
src/libide/libide.gresource.xml | 5 +
src/libide/meson.build | 1 +
src/libide/testing/ide-test-editor-addin.c | 106 +++++
src/libide/testing/ide-test-editor-addin.h | 29 ++
src/libide/testing/ide-test-manager.c | 569 +++++++++++++++++++++++++++
src/libide/testing/ide-test-manager.h | 45 +++
src/libide/testing/ide-test-panel.c | 192 +++++++++
src/libide/testing/ide-test-panel.h | 29 ++
src/libide/testing/ide-test-panel.ui | 24 ++
src/libide/testing/ide-test-private.h | 35 ++
src/libide/testing/ide-test-provider.c | 151 +++++++
src/libide/testing/ide-test-provider.h | 51 +++
src/libide/testing/ide-test.c | 313 +++++++++++++++
src/libide/testing/ide-test.h | 55 +++
src/libide/testing/meson.build | 23 ++
src/libide/testing/testing-plugin.c | 28 ++
src/libide/testing/testing.plugin | 9 +
src/plugins/meson/gbp-meson-test-provider.c | 40 ++
src/plugins/meson/gbp-meson-test-provider.h | 29 ++
src/plugins/meson/meson-plugin.c | 2 +
src/plugins/meson/meson.build | 2 +
25 files changed, 1794 insertions(+), 1 deletions(-)
---
diff --git a/src/libide/ide-context.c b/src/libide/ide-context.c
index 9e5a826..6ad0ced 100644
--- a/src/libide/ide-context.c
+++ b/src/libide/ide-context.c
@@ -39,6 +39,7 @@
#include "debugger/ide-debug-manager.h"
#include "devices/ide-device-manager.h"
#include "doap/ide-doap.h"
+#include "documentation/ide-documentation.h"
#include "plugins/ide-extension-util.h"
#include "projects/ide-project-files.h"
#include "projects/ide-project-item.h"
@@ -49,7 +50,7 @@
#include "search/ide-search-engine.h"
#include "search/ide-search-provider.h"
#include "snippets/ide-source-snippets-manager.h"
-#include "documentation/ide-documentation.h"
+#include "testing/ide-test-manager.h"
#include "transfers/ide-transfer-manager.h"
#include "util/ide-async-helper.h"
#include "util/ide-settings.h"
@@ -78,6 +79,7 @@ struct _IdeContext
IdeRuntimeManager *runtime_manager;
IdeSearchEngine *search_engine;
IdeSourceSnippetsManager *snippets_manager;
+ IdeTestManager *test_manager;
IdeProject *project;
GFile *project_file;
gchar *root_build_dir;
@@ -534,6 +536,7 @@ ide_context_finalize (GObject *object)
g_clear_object (&self->project_file);
g_clear_object (&self->recent_manager);
g_clear_object (&self->runtime_manager);
+ g_clear_object (&self->test_manager);
g_clear_object (&self->unsaved_files);
g_clear_object (&self->vcs);
@@ -817,6 +820,10 @@ ide_context_init (IdeContext *self)
"context", self,
NULL);
+ self->test_manager = g_object_new (IDE_TYPE_TEST_MANAGER,
+ "context", self,
+ NULL);
+
self->unsaved_files = g_object_new (IDE_TYPE_UNSAVED_FILES,
"context", self,
NULL);
@@ -1118,6 +1125,28 @@ ide_context_init_snippets (gpointer source_object,
}
static void
+ide_context_init_tests (gpointer source_object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdeContext *self = source_object;
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail (IDE_IS_CONTEXT (self));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+ g_task_set_source_tag (task, ide_context_init_tests);
+
+ if (!g_initable_init (G_INITABLE (self->test_manager), cancellable, &error))
+ g_task_return_error (task, g_steal_pointer (&error));
+ else
+ g_task_return_boolean (task, TRUE);
+}
+
+static void
ide_context_service_added (PeasExtensionSet *set,
PeasPluginInfo *info,
PeasExtension *exten,
@@ -1648,6 +1677,7 @@ ide_context_init_async (GAsyncInitable *initable,
ide_context_init_build_manager,
ide_context_init_run_manager,
ide_context_init_diagnostics_manager,
+ ide_context_init_tests,
ide_context_init_loaded,
NULL);
}
@@ -2320,6 +2350,24 @@ ide_context_get_debug_manager (IdeContext *self)
}
/**
+ * ide_context_get_test_manager:
+ * @self: An #IdeTestManager
+ *
+ * Gets the test manager for the #IdeContext.
+ *
+ * Returns: (transfer none): An #IdeTestManager
+ *
+ * Since: 3.28
+ */
+IdeTestManager *
+ide_context_get_test_manager (IdeContext *self)
+{
+ g_return_val_if_fail (IDE_IS_CONTEXT (self), NULL);
+
+ return self->test_manager;
+}
+
+/**
* ide_context_add_pausable:
* @self: an #IdeContext
* @pausable: an #IdePausable
diff --git a/src/libide/ide-context.h b/src/libide/ide-context.h
index e2a3351..5b5161e 100644
--- a/src/libide/ide-context.h
+++ b/src/libide/ide-context.h
@@ -47,6 +47,7 @@ IdeSettings *ide_context_get_settings (IdeContext
const gchar *schema_id,
const gchar *relative_path);
IdeSourceSnippetsManager *ide_context_get_snippets_manager (IdeContext *self);
+IdeTestManager *ide_context_get_test_manager (IdeContext *self);
IdeUnsavedFiles *ide_context_get_unsaved_files (IdeContext *self);
IdeVcs *ide_context_get_vcs (IdeContext *self);
const gchar *ide_context_get_root_build_dir (IdeContext *self);
diff --git a/src/libide/ide-types.h b/src/libide/ide-types.h
index 49a43de..72a05b6 100644
--- a/src/libide/ide-types.h
+++ b/src/libide/ide-types.h
@@ -129,6 +129,10 @@ typedef struct _IdeSubprocessLauncher IdeSubprocessLauncher;
typedef struct _IdeSymbol IdeSymbol;
typedef struct _IdeSymbolResolver IdeSymbolResolver;
+typedef struct _IdeTest IdeTest;
+typedef struct _IdeTestManager IdeTestManager;
+typedef struct _IdeTestProvider IdeTestProvider;
+
typedef struct _IdeTransferManager IdeTransferManager;
typedef struct _IdeTransfer IdeTransfer;
diff --git a/src/libide/ide.h b/src/libide/ide.h
index a12d853..61e2023 100644
--- a/src/libide/ide.h
+++ b/src/libide/ide.h
@@ -165,6 +165,8 @@ G_BEGIN_DECLS
#include "symbols/ide-tags-builder.h"
#include "template/ide-project-template.h"
#include "template/ide-template-provider.h"
+#include "testing/ide-test.h"
+#include "testing/ide-test-provider.h"
#include "threading/ide-thread-pool.h"
#include "transfers/ide-pkcon-transfer.h"
#include "transfers/ide-transfer.h"
diff --git a/src/libide/libide.gresource.xml b/src/libide/libide.gresource.xml
index a060e6a..8a34d85 100644
--- a/src/libide/libide.gresource.xml
+++ b/src/libide/libide.gresource.xml
@@ -81,6 +81,7 @@
<file preprocess="xml-stripblanks"
alias="ide-preferences-language-row.ui">preferences/ide-preferences-language-row.ui</file>
<file preprocess="xml-stripblanks"
alias="ide-preferences-window.ui">preferences/ide-preferences-window.ui</file>
<file preprocess="xml-stripblanks" alias="ide-run-button.ui">runner/ide-run-button.ui</file>
+ <file preprocess="xml-stripblanks" alias="ide-test-panel.ui">testing/ide-test-panel.ui</file>
<file preprocess="xml-stripblanks" alias="ide-transfer-row.ui">transfers/ide-transfer-row.ui</file>
<file preprocess="xml-stripblanks"
alias="ide-transfers-button.ui">transfers/ide-transfers-button.ui</file>
<file preprocess="xml-stripblanks"
alias="ide-shortcuts-window.ui">keybindings/ide-shortcuts-window.ui</file>
@@ -107,6 +108,10 @@
<file alias="directory.plugin">directory/directory.plugin</file>
</gresource>
+ <gresource prefix="/org/gnome/builder/plugins/testing">
+ <file alias="testing.plugin">testing/testing.plugin</file>
+ </gresource>
+
<gresource prefix="/org/gnome/builder/plugins/webkit">
<file alias="webkit.plugin">webkit/webkit.plugin</file>
</gresource>
diff --git a/src/libide/meson.build b/src/libide/meson.build
index 5e1473f..67fc7af 100644
--- a/src/libide/meson.build
+++ b/src/libide/meson.build
@@ -87,6 +87,7 @@ subdir('sourceview')
subdir('subprocess')
subdir('symbols')
subdir('template')
+subdir('testing')
subdir('threading')
subdir('transfers')
subdir('util')
diff --git a/src/libide/testing/ide-test-editor-addin.c b/src/libide/testing/ide-test-editor-addin.c
new file mode 100644
index 0000000..95adbb3
--- /dev/null
+++ b/src/libide/testing/ide-test-editor-addin.c
@@ -0,0 +1,106 @@
+/* ide-test-editor-addin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-test-editor-addin"
+
+#include <glib/gi18n.h>
+
+#include "ide-context.h"
+
+#include "editor/ide-editor-addin.h"
+#include "editor/ide-editor-perspective.h"
+#include "editor/ide-editor-sidebar.h"
+#include "testing/ide-test-editor-addin.h"
+#include "testing/ide-test-panel.h"
+#include "util/ide-gtk.h"
+
+struct _IdeTestEditorAddin
+{
+ GObject parent_instance;
+
+ IdeTestPanel *panel;
+};
+
+static void
+ide_test_editor_addin_load (IdeEditorAddin *addin,
+ IdeEditorPerspective *editor)
+{
+ IdeTestEditorAddin *self = (IdeTestEditorAddin *)addin;
+ IdeEditorSidebar *sidebar;
+ IdeTestManager *manager;
+ IdeContext *context;
+
+ g_assert (IDE_IS_TEST_EDITOR_ADDIN (self));
+ g_assert (IDE_IS_EDITOR_PERSPECTIVE (editor));
+
+ context = ide_widget_get_context (GTK_WIDGET (editor));
+ manager = ide_context_get_test_manager (context);
+
+ self->panel = g_object_new (IDE_TYPE_TEST_PANEL,
+ "manager", manager,
+ "visible", TRUE,
+ NULL);
+ g_signal_connect (self->panel,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroy),
+ &self->panel);
+
+ sidebar = ide_editor_perspective_get_sidebar (editor);
+
+ ide_editor_sidebar_add_section (sidebar,
+ "tests",
+ _("Unit Tests"),
+ "applications-science-symbolic",
+ NULL,
+ NULL,
+ GTK_WIDGET (self->panel),
+ 400);
+}
+
+static void
+ide_test_editor_addin_unload (IdeEditorAddin *addin,
+ IdeEditorPerspective *editor)
+{
+ IdeTestEditorAddin *self = (IdeTestEditorAddin *)addin;
+
+ g_assert (IDE_IS_TEST_EDITOR_ADDIN (self));
+ g_assert (IDE_IS_EDITOR_PERSPECTIVE (editor));
+
+ if (self->panel)
+ gtk_widget_destroy (GTK_WIDGET (self->panel));
+}
+
+static void
+editor_addin_iface_init (IdeEditorAddinInterface *iface)
+{
+ iface->load = ide_test_editor_addin_load;
+ iface->unload = ide_test_editor_addin_unload;
+}
+
+G_DEFINE_TYPE_WITH_CODE (IdeTestEditorAddin, ide_test_editor_addin, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_ADDIN, editor_addin_iface_init))
+
+static void
+ide_test_editor_addin_class_init (IdeTestEditorAddinClass *klass)
+{
+}
+
+static void
+ide_test_editor_addin_init (IdeTestEditorAddin *self)
+{
+}
diff --git a/src/libide/testing/ide-test-editor-addin.h b/src/libide/testing/ide-test-editor-addin.h
new file mode 100644
index 0000000..64fcf1d
--- /dev/null
+++ b/src/libide/testing/ide-test-editor-addin.h
@@ -0,0 +1,29 @@
+/* ide-test-editor-addin.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TEST_EDITOR_ADDIN (ide_test_editor_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeTestEditorAddin, ide_test_editor_addin, IDE, TEST_EDITOR_ADDIN, GObject)
+
+G_END_DECLS
diff --git a/src/libide/testing/ide-test-manager.c b/src/libide/testing/ide-test-manager.c
new file mode 100644
index 0000000..84dd098
--- /dev/null
+++ b/src/libide/testing/ide-test-manager.c
@@ -0,0 +1,569 @@
+/* ide-test-manager.c
+ *
+ * Copyright © 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-test-manager"
+
+#include <dazzle.h>
+#include <libpeas/peas.h>
+
+#include "ide-debug.h"
+
+#include "testing/ide-test-manager.h"
+#include "testing/ide-test-private.h"
+#include "testing/ide-test-provider.h"
+
+/**
+ * SECTION:ide-test-manager
+ * @title: IdeTestManager
+ * @short_description: Unit test discover and execution manager
+ *
+ * The #IdeTestManager is responsible for loading unit test provider
+ * plugins (via the #IdeTestProvider interface) and running those unit
+ * tests on behalf of the user.
+ *
+ * You can access the test manager using ide_context_get_text_manager()
+ * using the #IdeContext for the loaded project.
+ *
+ * Since: 3.28
+ */
+
+struct _IdeTestManager
+{
+ IdeObject parent_instance;
+ PeasExtensionSet *providers;
+ GPtrArray *tests_by_provider;
+ GtkTreeStore *tests_store;
+ guint busy : 1;
+};
+
+typedef struct
+{
+ IdeTestProvider *provider;
+ GPtrArray *tests;
+} TestsByProvider;
+
+enum {
+ PROP_0,
+ PROP_BUSY,
+ N_PROPS
+};
+
+static void initable_iface_init (GInitableIface *iface);
+static void ide_test_manager_actions_run_all (IdeTestManager *self,
+ GVariant *param);
+
+DZL_DEFINE_ACTION_GROUP (IdeTestManager, ide_test_manager, {
+ { "run-all", ide_test_manager_actions_run_all },
+})
+
+G_DEFINE_TYPE_WITH_CODE (IdeTestManager, ide_test_manager, IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
+ ide_test_manager_init_action_group))
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+tests_by_provider_free (gpointer data)
+{
+ TestsByProvider *info = data;
+
+ g_clear_pointer (&info->tests, g_ptr_array_unref);
+ g_clear_object (&info->provider);
+ g_slice_free (TestsByProvider, info);
+}
+
+static void
+ide_test_manager_dispose (GObject *object)
+{
+ IdeTestManager *self = (IdeTestManager *)object;
+
+ g_clear_object (&self->providers);
+ g_clear_object (&self->tests_store);
+ g_clear_pointer (&self->tests_by_provider, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (ide_test_manager_parent_class)->dispose (object);
+}
+
+static void
+ide_test_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTestManager *self = IDE_TEST_MANAGER (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUSY:
+ g_value_set_boolean (value, self->busy);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_test_manager_class_init (IdeTestManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = ide_test_manager_dispose;
+ object_class->get_property = ide_test_manager_get_property;
+
+ /**
+ * IdeTestManager:busy:
+ *
+ * The "busy" property indicates if the #IdeTestManager is currently
+ * processing various background unit tests.
+ *
+ * Since: 3.28
+ */
+ properties [PROP_BUSY] =
+ g_param_spec_boolean ("busy",
+ "Busy",
+ "If the test manager is busy processing",
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_test_manager_init (IdeTestManager *self)
+{
+ self->tests_by_provider = g_ptr_array_new_with_free_func (tests_by_provider_free);
+ self->tests_store = gtk_tree_store_new (2, G_TYPE_STRING, IDE_TYPE_TEST);
+}
+
+static void
+ide_test_manager_locate_group (IdeTestManager *self,
+ GtkTreeIter *iter,
+ const gchar *group)
+{
+ g_assert (IDE_IS_TEST_MANAGER (self));
+ g_assert (iter != NULL);
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->tests_store), iter))
+ {
+ do
+ {
+ g_autofree gchar *row_group = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (self->tests_store), iter,
+ IDE_TEST_COLUMN_GROUP, &row_group,
+ -1);
+
+ if (ide_str_equal0 (row_group, group))
+ return;
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->tests_store), iter));
+ }
+
+ /* TODO: Sort groups by name? */
+
+ gtk_tree_store_append (self->tests_store, iter, NULL);
+ gtk_tree_store_set (self->tests_store, iter,
+ IDE_TEST_COLUMN_GROUP, group,
+ -1);
+}
+
+static void
+ide_test_manager_add_test (IdeTestManager *self,
+ const TestsByProvider *info,
+ guint position,
+ IdeTest *test)
+{
+ const gchar *group;
+ GtkTreeIter iter;
+ GtkTreeIter parent;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TEST_MANAGER (self));
+ g_assert (info != NULL);
+ g_assert (IDE_IS_TEST (test));
+
+ g_ptr_array_insert (info->tests, position, g_object_ref (test));
+
+ group = ide_test_get_group (test);
+
+ ide_test_manager_locate_group (self, &parent, group);
+ gtk_tree_store_append (self->tests_store, &iter, &parent);
+ gtk_tree_store_set (self->tests_store, &iter,
+ IDE_TEST_COLUMN_GROUP, NULL,
+ IDE_TEST_COLUMN_TEST, test,
+ -1);
+
+ IDE_EXIT;
+}
+
+static void
+ide_test_manager_remove_test (IdeTestManager *self,
+ const TestsByProvider *info,
+ IdeTest *test)
+{
+ const gchar *group;
+ GtkTreeIter iter;
+ GtkTreeIter parent;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TEST_MANAGER (self));
+ g_assert (info != NULL);
+ g_assert (IDE_IS_TEST (test));
+
+ ide_test_manager_locate_group (self, &parent, group);
+
+ if (gtk_tree_model_iter_children (GTK_TREE_MODEL (self->tests_store), &iter, &parent))
+ {
+ do
+ {
+ g_autoptr(IdeTest) row = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (self->tests_store), &iter,
+ IDE_TEST_COLUMN_TEST, &row,
+ -1);
+
+ if (row == test)
+ {
+ gtk_tree_store_remove (self->tests_store, &iter);
+ break;
+ }
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->tests_store), &iter));
+ }
+
+ g_ptr_array_remove (info->tests, test);
+
+ IDE_EXIT;
+}
+
+static void
+ide_test_manager_provider_items_changed (IdeTestManager *self,
+ guint position,
+ guint removed,
+ guint added,
+ IdeTestProvider *provider)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TEST_MANAGER (self));
+ g_assert (IDE_IS_TEST_PROVIDER (provider));
+
+ for (guint i = 0; i < self->tests_by_provider->len; i++)
+ {
+ const TestsByProvider *info = g_ptr_array_index (self->tests_by_provider, i);
+
+ if (info->provider == provider)
+ {
+ /* Remove tests from cache that were deleted */
+ for (guint j = 0; j < removed; j++)
+ {
+ IdeTest *test = g_ptr_array_index (info->tests, position);
+ ide_test_manager_remove_test (self, info, test);
+ }
+
+ /* Add tests to cache that were added */
+ for (guint j = 0; j < added; j++)
+ {
+ g_autoptr(IdeTest) test = NULL;
+
+ test = g_list_model_get_item (G_LIST_MODEL (provider), position + j);
+ ide_test_manager_add_test (self, info, position + j, test);
+ }
+ }
+ }
+
+ IDE_EXIT;
+}
+
+static void
+ide_test_manager_provider_added (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ IdeTestManager *self = user_data;
+ IdeTestProvider *provider = (IdeTestProvider *)exten;
+ TestsByProvider *tests;
+ guint len;
+
+ IDE_ENTRY;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_TEST_PROVIDER (provider));
+ g_assert (G_IS_LIST_MODEL (provider));
+ g_assert (IDE_IS_TEST_MANAGER (self));
+
+ tests = g_slice_new0 (TestsByProvider);
+ tests->provider = g_object_ref (provider);
+ tests->tests = g_ptr_array_new_with_free_func (g_object_unref);
+ g_ptr_array_add (self->tests_by_provider, tests);
+
+ g_signal_connect_swapped (provider,
+ "items-changed",
+ G_CALLBACK (ide_test_manager_provider_items_changed),
+ self);
+
+ len = g_list_model_get_n_items (G_LIST_MODEL (provider));
+ ide_test_manager_provider_items_changed (self, 0, 0, len, provider);
+
+ IDE_EXIT;
+}
+
+static void
+ide_test_manager_provider_removed (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ IdeTestManager *self = user_data;
+ IdeTestProvider *provider = (IdeTestProvider *)exten;
+
+ IDE_ENTRY;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_TEST_PROVIDER (provider));
+ g_assert (IDE_IS_TEST_MANAGER (self));
+
+ for (guint i = 0; i < self->tests_by_provider->len; i++)
+ {
+ const TestsByProvider *info = g_ptr_array_index (self->tests_by_provider, i);
+
+ if (info->provider == provider)
+ {
+ g_ptr_array_remove_index (self->tests_by_provider, i);
+ break;
+ }
+ }
+
+ g_signal_handlers_disconnect_by_func (provider,
+ G_CALLBACK (ide_test_manager_provider_items_changed),
+ self);
+
+ IDE_EXIT;
+}
+
+static gboolean
+ide_test_manager_initiable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ IdeTestManager *self = (IdeTestManager *)initable;
+ IdeContext *context;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TEST_MANAGER (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+
+ self->providers = peas_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_TEST_PROVIDER,
+ "context", context,
+ NULL);
+
+ g_signal_connect (self->providers,
+ "extension-added",
+ G_CALLBACK (ide_test_manager_provider_added),
+ self);
+
+ g_signal_connect (self->providers,
+ "extension-removed",
+ G_CALLBACK (ide_test_manager_provider_removed),
+ self);
+
+ peas_extension_set_foreach (self->providers,
+ ide_test_manager_provider_added,
+ self);
+
+ IDE_RETURN (TRUE);
+}
+
+static void
+initable_iface_init (GInitableIface *iface)
+{
+ iface->init = ide_test_manager_initiable_init;
+}
+
+/**
+ * ide_test_manager_run_all_async:
+ * @self: An #IdeTestManager
+ * @cancellable: (nullable): A #GCancellable or %NULL
+ * @callback: a callback to execute upon completion
+ * @user_data: user data for @callback
+ *
+ * Executes all tests in an undefined order.
+ *
+ * Upon completion, @callback will be executed which must call
+ * ide_test_manager_run_all_finish() to get the result.
+ *
+ * Note that the individual test result information will be attached
+ * to the specific #IdeTest instances.
+ *
+ * Since: 3.28
+ */
+void
+ide_test_manager_run_all_async (IdeTestManager *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_TEST_MANAGER (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+ g_task_set_source_tag (task, ide_test_manager_run_all_async);
+
+ g_task_return_boolean (task, TRUE);
+
+ IDE_EXIT;
+}
+
+/**
+ * ide_test_manager_run_all_finish:
+ * @self: An #IdeTestManager
+ * @result: A #GAsyncResult
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to execute all unit tests.
+ *
+ * A return value of %TRUE does not indicate that all tests succeeded,
+ * only that all tests were executed. Individual test failures will be
+ * attached to the #IdeTest instances.
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ *
+ * Since: 3.28
+ */
+gboolean
+ide_test_manager_run_all_finish (IdeTestManager *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ gboolean ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_TEST_MANAGER (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ ret = g_task_propagate_boolean (G_TASK (result), error);
+
+ IDE_RETURN (ret);
+}
+
+/**
+ * ide_test_manager_run_async:
+ * @self: An #IdeTestManager
+ * @test: An #IdeTest
+ * @cancellable: (nullable): A #GCancellable, or %NULL
+ * @callback: a callback to execute upon completion
+ * @user_data: user data for @callback
+ *
+ * Executes a single unit test, asynchronously.
+ *
+ * The caller can access the result of the operation from @callback
+ * by calling ide_test_manager_run_finish() with the provided result.
+ *
+ * Since: 3.28
+ */
+void
+ide_test_manager_run_async (IdeTestManager *self,
+ IdeTest *test,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_TEST_MANAGER (self));
+ g_return_if_fail (IDE_IS_TEST (test));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+ g_task_set_source_tag (task, ide_test_manager_run_async);
+
+ g_task_return_boolean (task, TRUE);
+
+ IDE_EXIT;
+}
+
+/**
+ * ide_test_manager_run_finish:
+ * @self: An #IdeTestManager
+ * @result: The #GAsyncResult provided to callback
+ * @error: A location for a #GError, or %NULL
+ *
+ * Completes a request to ide_test_manager_run_finish().
+ *
+ * When this function returns %TRUE, it does not indicate that the test
+ * succeeded; only that the test was executed. Thest #IdeTest instance
+ * itself will contain information about the success of the test.
+ *
+ * Returns: %TRUE if the test was executed; otherwise %FALSE
+ * and @error is set.
+ *
+ * Since: 3.28
+ */
+gboolean
+ide_test_manager_run_finish (IdeTestManager *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ gboolean ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_TEST_MANAGER (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ ret = g_task_propagate_boolean (G_TASK (result), error);
+
+ IDE_RETURN (ret);
+}
+
+static void
+ide_test_manager_actions_run_all (IdeTestManager *self,
+ GVariant *param)
+{
+ g_assert (IDE_IS_TEST_MANAGER (self));
+
+ ide_test_manager_run_all_async (self, NULL, NULL, NULL);
+}
+
+GtkTreeModel *
+_ide_test_manager_get_model (IdeTestManager *self)
+{
+ g_return_val_if_fail (IDE_IS_TEST_MANAGER (self), NULL);
+
+ return GTK_TREE_MODEL (self->tests_store);
+}
diff --git a/src/libide/testing/ide-test-manager.h b/src/libide/testing/ide-test-manager.h
new file mode 100644
index 0000000..18f6ccd
--- /dev/null
+++ b/src/libide/testing/ide-test-manager.h
@@ -0,0 +1,45 @@
+/* ide-test-manager.h
+ *
+ * Copyright © 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ide-object.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TEST_MANAGER (ide_test_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeTestManager, ide_test_manager, IDE, TEST_MANAGER, IdeObject)
+
+void ide_test_manager_run_async (IdeTestManager *self,
+ IdeTest *test,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_test_manager_run_finish (IdeTestManager *self,
+ GAsyncResult *result,
+ GError **error);
+void ide_test_manager_run_all_async (IdeTestManager *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_test_manager_run_all_finish (IdeTestManager *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
diff --git a/src/libide/testing/ide-test-panel.c b/src/libide/testing/ide-test-panel.c
new file mode 100644
index 0000000..65ca6a4
--- /dev/null
+++ b/src/libide/testing/ide-test-panel.c
@@ -0,0 +1,192 @@
+/* ide-test-panel.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-test-panel"
+
+#include "testing/ide-test.h"
+#include "testing/ide-test-manager.h"
+#include "testing/ide-test-panel.h"
+#include "testing/ide-test-private.h"
+
+struct _IdeTestPanel
+{
+ GtkBin parent_instance;
+
+ IdeTestManager *manager;
+
+ GtkScrolledWindow *scroller;
+ GtkTreeView *tree_view;
+};
+
+enum {
+ PROP_0,
+ PROP_MANAGER,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (IdeTestPanel, ide_test_panel, GTK_TYPE_BIN)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_test_panel_cell_data_func (GtkCellLayout *layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ g_autofree gchar *title = NULL;
+ g_autoptr(IdeTest) test = NULL;
+
+ g_assert (GTK_IS_TREE_VIEW_COLUMN (layout));
+ g_assert (GTK_IS_CELL_RENDERER_TEXT (cell));
+ g_assert (GTK_IS_TREE_MODEL (model));
+ g_assert (iter != NULL);
+ g_assert (IDE_IS_TEST_PANEL (user_data));
+
+ gtk_tree_model_get (model, iter,
+ IDE_TEST_COLUMN_GROUP, &title,
+ IDE_TEST_COLUMN_TEST, &test,
+ -1);
+
+ if (title)
+ g_object_set (cell, "text", title, NULL);
+ else if (test)
+ g_object_set (cell, "text", ide_test_get_display_name (test), NULL);
+ else
+ g_object_set (cell, "text", NULL, NULL);
+
+ /* TODO: extract test info/failures/etc */
+}
+
+static void
+ide_test_panel_constructed (GObject *object)
+{
+ IdeTestPanel *self = (IdeTestPanel *)object;
+
+ g_assert (IDE_IS_TEST_PANEL (self));
+
+ G_OBJECT_CLASS (ide_test_panel_parent_class)->constructed (object);
+
+ if (self->manager != NULL)
+ {
+ GtkTreeModel *model;
+
+ model = _ide_test_manager_get_model (self->manager);
+ gtk_tree_view_set_model (self->tree_view, model);
+ }
+}
+
+static void
+ide_test_panel_destroy (GtkWidget *widget)
+{
+ IdeTestPanel *self = (IdeTestPanel *)widget;
+
+ g_assert (IDE_IS_TEST_PANEL (self));
+
+ g_clear_object (&self->manager);
+
+ GTK_WIDGET_CLASS (ide_test_panel_parent_class)->destroy (widget);
+}
+
+static void
+ide_test_panel_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTestPanel *self = IDE_TEST_PANEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_MANAGER:
+ g_value_set_object (value, self->manager);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_test_panel_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTestPanel *self = IDE_TEST_PANEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_MANAGER:
+ self->manager = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_test_panel_class_init (IdeTestPanelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->constructed = ide_test_panel_constructed;
+ object_class->get_property = ide_test_panel_get_property;
+ object_class->set_property = ide_test_panel_set_property;
+
+ widget_class->destroy = ide_test_panel_destroy;
+
+ properties [PROP_MANAGER] =
+ g_param_spec_object ("manager",
+ "Manager",
+ "The test manager for the panel",
+ IDE_TYPE_TEST_MANAGER,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/ide-test-panel.ui");
+ gtk_widget_class_bind_template_child (widget_class, IdeTestPanel, scroller);
+ gtk_widget_class_bind_template_child (widget_class, IdeTestPanel, tree_view);
+}
+
+static void
+ide_test_panel_init (IdeTestPanel *self)
+{
+ GtkCellRenderer *cell;
+ GtkTreeViewColumn *column;
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
+ "visible", TRUE,
+ NULL);
+ cell = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+ "xalign", 0.0f,
+ NULL);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ cell,
+ ide_test_panel_cell_data_func,
+ self,
+ NULL);
+ gtk_tree_view_append_column (self->tree_view, column);
+}
diff --git a/src/libide/testing/ide-test-panel.h b/src/libide/testing/ide-test-panel.h
new file mode 100644
index 0000000..92d8455
--- /dev/null
+++ b/src/libide/testing/ide-test-panel.h
@@ -0,0 +1,29 @@
+/* ide-test-panel.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TEST_PANEL (ide_test_panel_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeTestPanel, ide_test_panel, IDE, TEST_PANEL, GtkBin)
+
+G_END_DECLS
diff --git a/src/libide/testing/ide-test-panel.ui b/src/libide/testing/ide-test-panel.ui
new file mode 100644
index 0000000..b0618e3
--- /dev/null
+++ b/src/libide/testing/ide-test-panel.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="IdeTestPanel" parent="GtkBin">
+ <child>
+ <object class="GtkScrolledWindow" id="scroller">
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkTreeView" id="tree_view">
+ <property name="headers-visible">false</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="i-wanna-be-listbox"/>
+ </style>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection">
+ <property name="mode">none</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/libide/testing/ide-test-private.h b/src/libide/testing/ide-test-private.h
new file mode 100644
index 0000000..8520f07
--- /dev/null
+++ b/src/libide/testing/ide-test-private.h
@@ -0,0 +1,35 @@
+/* ide-test-private.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "ide-test-manager.h"
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ IDE_TEST_COLUMN_GROUP,
+ IDE_TEST_COLUMN_TEST,
+} IdeTestColumn;
+
+GtkTreeModel *_ide_test_manager_get_model (IdeTestManager *self);
+
+G_END_DECLS
diff --git a/src/libide/testing/ide-test-provider.c b/src/libide/testing/ide-test-provider.c
new file mode 100644
index 0000000..0903c56
--- /dev/null
+++ b/src/libide/testing/ide-test-provider.c
@@ -0,0 +1,151 @@
+/* ide-test-provider.c
+ *
+ * Copyright © 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-test-provider"
+
+#include "testing/ide-test-provider.h"
+
+typedef struct
+{
+ GPtrArray *items;
+} IdeTestProviderPrivate;
+
+static void list_model_iface_init (GListModelInterface *iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (IdeTestProvider, ide_test_provider, IDE_TYPE_OBJECT,
+ G_ADD_PRIVATE (IdeTestProvider)
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
+
+static void
+ide_test_provider_dispose (GObject *object)
+{
+ IdeTestProvider *self = (IdeTestProvider *)object;
+ IdeTestProviderPrivate *priv = ide_test_provider_get_instance_private (self);
+
+ if (priv->items != NULL && priv->items->len > 0)
+ {
+ guint len = priv->items->len;
+
+ g_ptr_array_remove_range (priv->items, 0, len);
+ g_list_model_items_changed (G_LIST_MODEL (self), 0, len, 0);
+ }
+
+ g_clear_pointer (&priv->items, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (ide_test_provider_parent_class)->finalize (object);
+}
+
+static void
+ide_test_provider_class_init (IdeTestProviderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = ide_test_provider_dispose;
+}
+
+static void
+ide_test_provider_init (IdeTestProvider *self)
+{
+ IdeTestProviderPrivate *priv = ide_test_provider_get_instance_private (self);
+
+ priv->items = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+static GType
+ide_test_provider_get_item_type (GListModel *model)
+{
+ return IDE_TYPE_TEST;
+}
+
+static guint
+ide_test_provider_get_n_items (GListModel *model)
+{
+ IdeTestProvider *self = (IdeTestProvider *)model;
+ IdeTestProviderPrivate *priv = ide_test_provider_get_instance_private (self);
+
+ g_assert (IDE_IS_TEST_PROVIDER (self));
+
+ return priv->items ? priv->items->len : 0;
+}
+
+static gpointer
+ide_test_provider_get_item (GListModel *model,
+ guint position)
+{
+ IdeTestProvider *self = (IdeTestProvider *)model;
+ IdeTestProviderPrivate *priv = ide_test_provider_get_instance_private (self);
+
+ g_assert (IDE_IS_TEST_PROVIDER (self));
+
+ if (priv->items != NULL)
+ {
+ if (position < priv->items->len)
+ return g_object_ref (g_ptr_array_index (priv->items, position));
+ }
+
+ return NULL;
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+ iface->get_item = ide_test_provider_get_item;
+ iface->get_n_items = ide_test_provider_get_n_items;
+ iface->get_item_type = ide_test_provider_get_item_type;
+}
+
+void
+ide_test_provider_add (IdeTestProvider *self,
+ IdeTest *test)
+{
+ IdeTestProviderPrivate *priv = ide_test_provider_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_TEST_PROVIDER (self));
+ g_return_if_fail (IDE_IS_TEST (test));
+
+ if (priv->items != NULL)
+ {
+ g_ptr_array_add (priv->items, g_object_ref (test));
+ g_list_model_items_changed (G_LIST_MODEL (self), priv->items->len - 1, 0, 1);
+ }
+}
+
+void
+ide_test_provider_remove (IdeTestProvider *self,
+ IdeTest *test)
+{
+ IdeTestProviderPrivate *priv = ide_test_provider_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_TEST_PROVIDER (self));
+ g_return_if_fail (IDE_IS_TEST (test));
+
+ if (priv->items != NULL)
+ {
+ for (guint i = 0; i < priv->items->len; i++)
+ {
+ IdeTest *element = g_ptr_array_index (priv->items, i);
+
+ if (element == test)
+ {
+ g_ptr_array_remove_index (priv->items, i);
+ g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/libide/testing/ide-test-provider.h b/src/libide/testing/ide-test-provider.h
new file mode 100644
index 0000000..cc3e5fd
--- /dev/null
+++ b/src/libide/testing/ide-test-provider.h
@@ -0,0 +1,51 @@
+/* ide-test-provider.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ide-object.h"
+
+#include "testing/ide-test.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TEST_PROVIDER (ide_test_provider_get_type ())
+
+G_DECLARE_DERIVABLE_TYPE (IdeTestProvider, ide_test_provider, IDE, TEST_PROVIDER, IdeObject)
+
+struct _IdeTestProviderClass
+{
+ IdeObjectClass parent_class;
+
+ /*< private >*/
+ gpointer _reserved1;
+ gpointer _reserved2;
+ gpointer _reserved3;
+ gpointer _reserved4;
+ gpointer _reserved5;
+ gpointer _reserved6;
+ gpointer _reserved7;
+ gpointer _reserved8;
+};
+
+void ide_test_provider_add (IdeTestProvider *self,
+ IdeTest *test);
+void ide_test_provider_remove (IdeTestProvider *self,
+ IdeTest *test);
+
+G_END_DECLS
diff --git a/src/libide/testing/ide-test.c b/src/libide/testing/ide-test.c
new file mode 100644
index 0000000..e5838b3
--- /dev/null
+++ b/src/libide/testing/ide-test.c
@@ -0,0 +1,313 @@
+/* ide-test.c
+ *
+ * Copyright © 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ide-test.h"
+
+typedef struct
+{
+ gchar *display_name;
+ gchar *group;
+ gchar *id;
+} IdeTestPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdeTest, ide_test, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_DISPLAY_NAME,
+ PROP_GROUP,
+ PROP_ID,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+IdeTest *
+ide_test_new (void)
+{
+ return g_object_new (IDE_TYPE_TEST, NULL);
+}
+
+static void
+ide_test_finalize (GObject *object)
+{
+ IdeTest *self = (IdeTest *)object;
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_clear_pointer (&priv->group, g_free);
+ g_clear_pointer (&priv->id, g_free);
+ g_clear_pointer (&priv->display_name, g_free);
+
+ G_OBJECT_CLASS (ide_test_parent_class)->finalize (object);
+}
+
+static void
+ide_test_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTest *self = IDE_TEST (object);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, ide_test_get_id (self));
+ break;
+
+ case PROP_GROUP:
+ g_value_set_string (value, ide_test_get_group (self));
+ break;
+
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value, ide_test_get_display_name (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_test_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeTest *self = IDE_TEST (object);
+
+ switch (prop_id)
+ {
+ case PROP_GROUP:
+ ide_test_set_group (self, g_value_get_string (value));
+ break;
+
+ case PROP_ID:
+ ide_test_set_id (self, g_value_get_string (value));
+ break;
+
+ case PROP_DISPLAY_NAME:
+ ide_test_set_display_name (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_test_class_init (IdeTestClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_test_finalize;
+ object_class->get_property = ide_test_get_property;
+ object_class->set_property = ide_test_set_property;
+
+ /**
+ * IdeTest:display_name:
+ *
+ * The "display-name" property contains the display name of the test as
+ * the user is expected to read in UI elements.
+ *
+ * Since: 3.28
+ */
+ properties [PROP_DISPLAY_NAME] =
+ g_param_spec_string ("display-name",
+ "Name",
+ "The display_name of the unit test",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * IdeTest:id:
+ *
+ * The "id" property contains the unique identifier of the test.
+ *
+ * Since: 3.28
+ */
+ properties [PROP_ID] =
+ g_param_spec_string ("id",
+ "Id",
+ "The unique identifier of the test",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * IdeTest:group:
+ *
+ * The "group" property contains the name of the gruop the test belongs
+ * to, if any.
+ *
+ * Since: 3.28
+ */
+ properties [PROP_GROUP] =
+ g_param_spec_string ("group",
+ "Group",
+ "The name of the group the test belongs to, if any",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_test_init (IdeTest *self)
+{
+}
+
+/**
+ * ide_test_get_display_name:
+ * @self: An #IdeTest
+ *
+ * Gets the "display-name" property of the test.
+ *
+ * Returns: (nullable): The display_name of the test or %NULL
+ *
+ * Since: 3.28
+ */
+const gchar *
+ide_test_get_display_name (IdeTest *self)
+{
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_TEST (self), NULL);
+
+ return priv->display_name;
+}
+
+/**
+ * ide_test_set_display_name:
+ * @self: An #IdeTest
+ * @display_name: (nullable): The display_name of the test, or %NULL to unset
+ *
+ * Sets the "display-name" property of the unit test.
+ *
+ * Since: 3.28
+ */
+void
+ide_test_set_display_name (IdeTest *self,
+ const gchar *display_name)
+{
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_TEST (self));
+
+ if (g_strcmp0 (display_name, priv->display_name) != 0)
+ {
+ g_free (priv->display_name);
+ priv->display_name = g_strdup (display_name);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
+ }
+}
+
+/**
+ * ide_test_get_group:
+ * @self: a #IdeTest
+ *
+ * Gets the "group" property.
+ *
+ * The group name is used to group tests together.
+ *
+ * Returns: (nullable): The group name or %NULL.
+ *
+ * Since: 3.28
+ */
+const gchar *
+ide_test_get_group (IdeTest *self)
+{
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_TEST (self), NULL);
+
+ return priv->group;
+}
+
+/**
+ * ide_test_set_group:
+ * @self: a #IdeTest
+ * @group: (nullable): the name of the group or %NULL
+ *
+ * Sets the #IdeTest:group property.
+ *
+ * The group property is used to group related tests together.
+ *
+ * Since: 3.28
+ */
+void
+ide_test_set_group (IdeTest *self,
+ const gchar *group)
+{
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_TEST (self));
+
+ if (g_strcmp0 (group, priv->group) != 0)
+ {
+ g_free (priv->group);
+ priv->group = g_strdup (group);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_GROUP]);
+ }
+}
+
+/**
+ * ide_test_get_id:
+ * @self: a #IdeTest
+ *
+ * Gets the #IdeTest:id property.
+ *
+ * Returns: (nullable): The id of the test, or %NULL if it has not been set.
+ *
+ * Since: 3.28
+ */
+const gchar *
+ide_test_get_id (IdeTest *self)
+{
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_TEST (self), NULL);
+
+ return priv->id;
+}
+
+/**
+ * ide_test_set_id:
+ * @self: a #IdeTest
+ * @id: (nullable): the id of the test or %NULL
+ *
+ * Sets the #IdeTest:id property.
+ *
+ * The id property is used to uniquely identify the test.
+ *
+ * Since: 3.28
+ */
+void
+ide_test_set_id (IdeTest *self,
+ const gchar *id)
+{
+ IdeTestPrivate *priv = ide_test_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_TEST (self));
+
+ if (g_strcmp0 (id, priv->id) != 0)
+ {
+ g_free (priv->id);
+ priv->id = g_strdup (id);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
+ }
+}
diff --git a/src/libide/testing/ide-test.h b/src/libide/testing/ide-test.h
new file mode 100644
index 0000000..6e1702b
--- /dev/null
+++ b/src/libide/testing/ide-test.h
@@ -0,0 +1,55 @@
+/* ide-test.h
+ *
+ * Copyright © 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TEST (ide_test_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (IdeTest, ide_test, IDE, TEST, GObject)
+
+struct _IdeTestClass
+{
+ GObjectClass parent;
+
+ /*< private >*/
+ gpointer _reserved1;
+ gpointer _reserved2;
+ gpointer _reserved3;
+ gpointer _reserved4;
+ gpointer _reserved5;
+ gpointer _reserved6;
+ gpointer _reserved7;
+ gpointer _reserved8;
+};
+
+IdeTest *ide_test_new (void);
+const gchar *ide_test_get_display_name (IdeTest *self);
+void ide_test_set_display_name (IdeTest *self,
+ const gchar *display_name);
+const gchar *ide_test_get_group (IdeTest *self);
+void ide_test_set_group (IdeTest *self,
+ const gchar *group);
+const gchar *ide_test_get_id (IdeTest *self);
+void ide_test_set_id (IdeTest *self,
+ const gchar *id);
+
+G_END_DECLS
diff --git a/src/libide/testing/meson.build b/src/libide/testing/meson.build
new file mode 100644
index 0000000..640ebe5
--- /dev/null
+++ b/src/libide/testing/meson.build
@@ -0,0 +1,23 @@
+testing_headers = [
+ 'ide-test.h',
+ 'ide-test-manager.h',
+ 'ide-test-provider.h',
+]
+
+testing_sources = [
+ 'ide-test.c',
+ 'ide-test-manager.c',
+ 'ide-test-provider.c',
+]
+
+testing_private_sources = [
+ 'ide-test-panel.c',
+ 'ide-test-editor-addin.c',
+ 'testing-plugin.c',
+]
+
+libide_public_headers += files(testing_headers)
+libide_public_sources += files(testing_sources)
+libide_private_sources += files(testing_private_sources)
+
+install_headers(testing_headers, subdir: join_paths(libide_header_subdir, 'testing'))
diff --git a/src/libide/testing/testing-plugin.c b/src/libide/testing/testing-plugin.c
new file mode 100644
index 0000000..6db5872
--- /dev/null
+++ b/src/libide/testing/testing-plugin.c
@@ -0,0 +1,28 @@
+/* testing-plugin.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libpeas/peas.h>
+
+#include "editor/ide-editor-addin.h"
+#include "testing/ide-test-editor-addin.h"
+
+void
+ide_test_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module, IDE_TYPE_EDITOR_ADDIN, IDE_TYPE_TEST_EDITOR_ADDIN);
+}
diff --git a/src/libide/testing/testing.plugin b/src/libide/testing/testing.plugin
new file mode 100644
index 0000000..89802f2
--- /dev/null
+++ b/src/libide/testing/testing.plugin
@@ -0,0 +1,9 @@
+[Plugin]
+Module=testing
+Name=Testing
+Description=Unit testing for Builder
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2017 Christian Hergert
+Builtin=true
+Hidden=true
+Embedded=ide_test_register_types
diff --git a/src/plugins/meson/gbp-meson-test-provider.c b/src/plugins/meson/gbp-meson-test-provider.c
new file mode 100644
index 0000000..5c3ed8c
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-test-provider.c
@@ -0,0 +1,40 @@
+/* gbp-meson-test-provider.c
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-meson-test-provider"
+
+#include <json-glib/json-glib.h>
+
+#include "gbp-meson-test-provider.h"
+
+struct _GbpMesonTestProvider
+{
+ IdeTestProvider parent_instance;
+};
+
+G_DEFINE_TYPE (GbpMesonTestProvider, gbp_meson_test_provider, IDE_TYPE_TEST_PROVIDER)
+
+static void
+gbp_meson_test_provider_class_init (GbpMesonTestProviderClass *klass)
+{
+}
+
+static void
+gbp_meson_test_provider_init (GbpMesonTestProvider *self)
+{
+}
diff --git a/src/plugins/meson/gbp-meson-test-provider.h b/src/plugins/meson/gbp-meson-test-provider.h
new file mode 100644
index 0000000..40e111a
--- /dev/null
+++ b/src/plugins/meson/gbp-meson-test-provider.h
@@ -0,0 +1,29 @@
+/* gbp-meson-test-provider.h
+ *
+ * Copyright (C) 2017 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_MESON_TEST_PROVIDER (gbp_meson_test_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpMesonTestProvider, gbp_meson_test_provider, GBP, MESON_TEST_PROVIDER,
IdeTestProvider)
+
+G_END_DECLS
diff --git a/src/plugins/meson/meson-plugin.c b/src/plugins/meson/meson-plugin.c
index 36bd525..7090063 100644
--- a/src/plugins/meson/meson-plugin.c
+++ b/src/plugins/meson/meson-plugin.c
@@ -21,10 +21,12 @@
#include "gbp-meson-build-system.h"
#include "gbp-meson-pipeline-addin.h"
+#include "gbp-meson-test-provider.h"
void
gbp_meson_register_types (PeasObjectModule *module)
{
peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_PIPELINE_ADDIN,
GBP_TYPE_MESON_PIPELINE_ADDIN);
peas_object_module_register_extension_type (module, IDE_TYPE_BUILD_SYSTEM, GBP_TYPE_MESON_BUILD_SYSTEM);
+ peas_object_module_register_extension_type (module, IDE_TYPE_TEST_PROVIDER, GBP_TYPE_MESON_TEST_PROVIDER);
}
diff --git a/src/plugins/meson/meson.build b/src/plugins/meson/meson.build
index 763ab8e..a0c4ff3 100644
--- a/src/plugins/meson/meson.build
+++ b/src/plugins/meson/meson.build
@@ -14,6 +14,8 @@ meson_sources = [
'gbp-meson-build-target.h',
'gbp-meson-pipeline-addin.c',
'gbp-meson-pipeline-addin.h',
+ 'gbp-meson-test-provider.c',
+ 'gbp-meson-test-provider.h',
]
gnome_builder_plugins_sources += files(meson_sources)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]