[gnome-builder/wip/gtk4-port] plugins/testui: put unit tests in a virtual folder



commit 922e1742ca4f6329c55a0410ba32f78d30cac8ac
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jul 7 15:02:45 2022 -0700

    plugins/testui: put unit tests in a virtual folder
    
    This is also the first step towards having things like context menus to
    run under the debugger, etc.

 src/plugins/testui/gbp-testui-item.c            | 244 ++++++++++++++++++++++++
 src/plugins/testui/gbp-testui-item.h            |  38 ++++
 src/plugins/testui/gbp-testui-panel.c           | 132 +++++--------
 src/plugins/testui/gbp-testui-panel.h           |   3 +-
 src/plugins/testui/gbp-testui-panel.ui          |  14 +-
 src/plugins/testui/gbp-testui-workspace-addin.c |   5 +-
 src/plugins/testui/meson.build                  |   3 +-
 7 files changed, 346 insertions(+), 93 deletions(-)
---
diff --git a/src/plugins/testui/gbp-testui-item.c b/src/plugins/testui/gbp-testui-item.c
new file mode 100644
index 000000000..ee006f90a
--- /dev/null
+++ b/src/plugins/testui/gbp-testui-item.c
@@ -0,0 +1,244 @@
+/* gbp-testui-item.c
+ *
+ * Copyright 2022 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-testui-item"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-foundry.h>
+
+#include "gbp-testui-item.h"
+
+struct _GbpTestuiItem
+{
+  GObject  parent_instance;
+  gpointer instance;
+};
+
+enum {
+  PROP_0,
+  PROP_ICON_NAME,
+  PROP_EXPANDED_ICON_NAME,
+  PROP_INSTANCE,
+  PROP_TITLE,
+  N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (GbpTestuiItem, gbp_testui_item, G_TYPE_OBJECT)
+
+static GParamSpec *properties [N_PROPS];
+
+static const char *
+gbp_testui_item_get_icon_name (GbpTestuiItem *self)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_TESTUI_ITEM (self));
+
+  if (IDE_IS_TEST_MANAGER (self->instance))
+    return "folder-symbolic";
+
+  if (IDE_IS_TEST (self->instance))
+    return ide_test_get_icon_name (self->instance);
+
+  return NULL;
+}
+
+static const char *
+gbp_testui_item_get_expanded_icon_name (GbpTestuiItem *self)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_TESTUI_ITEM (self));
+
+  if (IDE_IS_TEST_MANAGER (self->instance))
+    return "folder-open-symbolic";
+
+  return gbp_testui_item_get_icon_name (self);
+}
+
+static const char *
+gbp_testui_item_get_title (GbpTestuiItem *self)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_TESTUI_ITEM (self));
+
+  if (IDE_IS_TEST_MANAGER (self->instance))
+    return _("Unit Tests");
+
+  if (IDE_IS_TEST (self->instance))
+    return ide_test_get_title (self->instance);
+
+  return NULL;
+}
+
+static void
+gbp_testui_item_dispose (GObject *object)
+{
+  GbpTestuiItem *self = (GbpTestuiItem *)object;
+
+  g_clear_object (&self->instance);
+
+  G_OBJECT_CLASS (gbp_testui_item_parent_class)->dispose (object);
+}
+
+static void
+gbp_testui_item_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GbpTestuiItem *self = GBP_TESTUI_ITEM (object);
+
+  switch (prop_id)
+    {
+    case PROP_INSTANCE:
+      g_value_set_object (value, self->instance);
+      break;
+
+    case PROP_ICON_NAME:
+      g_value_set_static_string (value, g_intern_string (gbp_testui_item_get_icon_name (self)));
+      break;
+
+    case PROP_EXPANDED_ICON_NAME:
+      g_value_set_static_string (value, g_intern_string (gbp_testui_item_get_expanded_icon_name (self)));
+      break;
+
+    case PROP_TITLE:
+      g_value_set_string (value, gbp_testui_item_get_title (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_testui_item_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GbpTestuiItem *self = GBP_TESTUI_ITEM (object);
+
+  switch (prop_id)
+    {
+    case PROP_INSTANCE:
+      self->instance = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_testui_item_class_init (GbpTestuiItemClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = gbp_testui_item_dispose;
+  object_class->get_property = gbp_testui_item_get_property;
+  object_class->set_property = gbp_testui_item_set_property;
+
+  properties [PROP_INSTANCE] =
+    g_param_spec_object ("instance", NULL, NULL,
+                         G_TYPE_OBJECT,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_EXPANDED_ICON_NAME] =
+    g_param_spec_string ("expanded-icon-name", NULL, NULL,
+                         NULL,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_ICON_NAME] =
+    g_param_spec_string ("icon-name", NULL, NULL,
+                         NULL,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_TITLE] =
+    g_param_spec_string ("title", NULL, NULL,
+                         NULL,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_testui_item_init (GbpTestuiItem *self)
+{
+}
+
+GbpTestuiItem *
+gbp_testui_item_new (gpointer instance)
+{
+  g_return_val_if_fail (G_IS_OBJECT (instance), NULL);
+
+  g_assert (IDE_IS_TEST (instance) ||
+            IDE_IS_TEST_MANAGER (instance));
+
+  g_print ("%s\n", G_OBJECT_TYPE_NAME (instance));
+
+  return g_object_new (GBP_TYPE_TESTUI_ITEM,
+                       "instance", instance,
+                       NULL);
+}
+
+gpointer
+gbp_testui_item_map_func (gpointer item,
+                          gpointer user_data)
+{
+  gpointer ret = gbp_testui_item_new (item);
+  g_object_unref (item);
+  return ret;
+}
+
+GListModel *
+gbp_testui_item_create_child_model (gpointer item,
+                                    gpointer user_data)
+{
+  GbpTestuiItem *self = item;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (GBP_IS_TESTUI_ITEM (self), NULL);
+
+  if (IDE_IS_TEST_MANAGER (self->instance))
+    {
+      GListModel *tests = ide_test_manager_list_tests (self->instance);
+      return G_LIST_MODEL (gtk_map_list_model_new (g_object_ref (tests),
+                                                   gbp_testui_item_map_func,
+                                                   NULL, NULL));
+    }
+
+  /* TODO: We could insert information about the test run here, like
+   *       a list of passed or failed tests if we have a protocol to
+   *       extract that from the unit test.
+   */
+
+  return NULL;
+}
+
+gpointer
+gbp_testui_item_get_instance (GbpTestuiItem *self)
+{
+  g_return_val_if_fail (GBP_IS_TESTUI_ITEM (self), NULL);
+
+  return self->instance;
+}
diff --git a/src/plugins/testui/gbp-testui-item.h b/src/plugins/testui/gbp-testui-item.h
new file mode 100644
index 000000000..3573b42ac
--- /dev/null
+++ b/src/plugins/testui/gbp-testui-item.h
@@ -0,0 +1,38 @@
+/* gbp-testui-item.h
+ *
+ * Copyright 2022 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_TESTUI_ITEM (gbp_testui_item_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpTestuiItem, gbp_testui_item, GBP, TESTUI_ITEM, GObject)
+
+GbpTestuiItem *gbp_testui_item_new                (gpointer       instance);
+gpointer       gbp_testui_item_get_instance       (GbpTestuiItem *self);
+GListModel    *gbp_testui_item_create_child_model (gpointer       item,
+                                                   gpointer       user_data);
+gpointer       gbp_testui_item_map_func           (gpointer       item,
+                                                   gpointer       user_data);
+
+G_END_DECLS
diff --git a/src/plugins/testui/gbp-testui-panel.c b/src/plugins/testui/gbp-testui-panel.c
index 12387be78..f2787ba3c 100644
--- a/src/plugins/testui/gbp-testui-panel.c
+++ b/src/plugins/testui/gbp-testui-panel.c
@@ -24,117 +24,94 @@
 
 #include <libide-foundry.h>
 
+#include "gbp-testui-item.h"
 #include "gbp-testui-panel.h"
 
 struct _GbpTestuiPanel
 {
-  IdePane          parent_instance;
-
-  GtkListView    *list_view;
-  GtkNoSelection *selection;
-
-  GListModel      *model;
+  IdePane           parent_instance;
+  GtkNoSelection   *selection;
+  GtkTreeListModel *tree_model;
 };
 
 G_DEFINE_FINAL_TYPE (GbpTestuiPanel, gbp_testui_panel, IDE_TYPE_PANE)
 
-enum {
-  PROP_0,
-  PROP_MODEL,
-  N_PROPS
-};
-
 enum {
   TEST_ACTIVATED,
   N_SIGNALS
 };
 
-static GParamSpec *properties[N_PROPS];
 static guint signals[N_SIGNALS];
 
 static void
-gbp_testui_panel_activate_cb (GbpTestuiPanel *self,
-                              guint           position,
-                              GtkListView    *list_view)
+gbp_testui_panel_set_test_manager (GbpTestuiPanel *self,
+                                   IdeTestManager *test_manager)
 {
-  GtkSelectionModel *model;
-  g_autoptr(IdeTest) test = NULL;
+  g_autoptr(GbpTestuiItem) item = NULL;
+  GListStore *store;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_TESTUI_PANEL (self));
-  g_assert (GTK_IS_LIST_VIEW (list_view));
+  g_assert (IDE_IS_TEST_MANAGER (test_manager));
+  g_assert (self->tree_model == NULL);
 
-  model = gtk_list_view_get_model (list_view);
-  test = g_list_model_get_item (G_LIST_MODEL (model), position);
+  store = g_list_store_new (GBP_TYPE_TESTUI_ITEM);
+  item = gbp_testui_item_new (test_manager);
+  g_list_store_append (store, item);
+
+  self->tree_model = gtk_tree_list_model_new (G_LIST_MODEL (store),
+                                              FALSE, TRUE,
+                                              gbp_testui_item_create_child_model,
+                                              NULL, NULL);
+  gtk_no_selection_set_model (self->selection, G_LIST_MODEL (self->tree_model));
 
-  g_signal_emit (self, signals[TEST_ACTIVATED], 0, test);
 
   IDE_EXIT;
 }
 
 static void
-gbp_testui_panel_set_model (GbpTestuiPanel *self,
-                            GListModel     *model)
+gbp_testui_panel_activate_cb (GbpTestuiPanel *self,
+                              guint           position,
+                              GtkListView    *list_view)
 {
+  g_autoptr(GtkTreeListRow) row = NULL;
+  GtkSelectionModel *model;
+  GbpTestuiItem *item;
+  gpointer instance;
+
+  IDE_ENTRY;
+
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_TESTUI_PANEL (self));
-  g_assert (!model || G_IS_LIST_MODEL (model));
-
-  if (g_set_object (&self->model, model))
-    {
-      gtk_no_selection_set_model (self->selection, model);
-      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
-    }
-}
+  g_assert (GTK_IS_LIST_VIEW (list_view));
 
-static void
-gbp_testui_panel_dispose (GObject *object)
-{
-  GbpTestuiPanel *self = (GbpTestuiPanel *)object;
+  model = gtk_list_view_get_model (list_view);
 
-  g_clear_object (&self->model);
+  row = g_list_model_get_item (G_LIST_MODEL (model), position);
+  g_assert (GTK_IS_TREE_LIST_ROW (row));
 
-  G_OBJECT_CLASS (gbp_testui_panel_parent_class)->dispose (object);
-}
+  item = gtk_tree_list_row_get_item (row);
+  g_assert (GBP_IS_TESTUI_ITEM (item));
 
-static void
-gbp_testui_panel_get_property (GObject    *object,
-                               guint       prop_id,
-                               GValue     *value,
-                               GParamSpec *pspec)
-{
-  GbpTestuiPanel *self = GBP_TESTUI_PANEL (object);
+  instance = gbp_testui_item_get_instance (item);
+  g_assert (G_IS_OBJECT (instance));
 
-  switch (prop_id)
-    {
-    case PROP_MODEL:
-      g_value_set_object (value, self->model);
-      break;
+  if (IDE_IS_TEST (instance))
+    g_signal_emit (self, signals[TEST_ACTIVATED], 0, instance);
 
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  IDE_EXIT;
 }
 
 static void
-gbp_testui_panel_set_property (GObject      *object,
-                               guint         prop_id,
-                               const GValue *value,
-                               GParamSpec   *pspec)
+gbp_testui_panel_dispose (GObject *object)
 {
-  GbpTestuiPanel *self = GBP_TESTUI_PANEL (object);
+  GbpTestuiPanel *self = (GbpTestuiPanel *)object;
 
-  switch (prop_id)
-    {
-    case PROP_MODEL:
-      gbp_testui_panel_set_model (self, g_value_get_object (value));
-      break;
+  g_clear_object (&self->tree_model);
 
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  G_OBJECT_CLASS (gbp_testui_panel_parent_class)->dispose (object);
 }
 
 static void
@@ -144,15 +121,6 @@ gbp_testui_panel_class_init (GbpTestuiPanelClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
   object_class->dispose = gbp_testui_panel_dispose;
-  object_class->get_property = gbp_testui_panel_get_property;
-  object_class->set_property = gbp_testui_panel_set_property;
-
-  properties [PROP_MODEL] =
-    g_param_spec_object ("model", NULL, NULL,
-                         G_TYPE_LIST_MODEL,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_properties (object_class, N_PROPS, properties);
 
   signals[TEST_ACTIVATED] =
     g_signal_new ("test-activated",
@@ -164,7 +132,6 @@ gbp_testui_panel_class_init (GbpTestuiPanelClass *klass)
                   G_TYPE_NONE, 1, IDE_TYPE_TEST);
 
   gtk_widget_class_set_template_from_resource (widget_class, "/plugins/testui/gbp-testui-panel.ui");
-  gtk_widget_class_bind_template_child (widget_class, GbpTestuiPanel, list_view);
   gtk_widget_class_bind_template_child (widget_class, GbpTestuiPanel, selection);
   gtk_widget_class_bind_template_callback (widget_class, gbp_testui_panel_activate_cb);
 }
@@ -176,7 +143,14 @@ gbp_testui_panel_init (GbpTestuiPanel *self)
 }
 
 GbpTestuiPanel *
-gbp_testui_panel_new (void)
+gbp_testui_panel_new (IdeTestManager *test_manager)
 {
-  return g_object_new (GBP_TYPE_TESTUI_PANEL, NULL);
+  GbpTestuiPanel *self;
+
+  g_return_val_if_fail (IDE_IS_TEST_MANAGER (test_manager), NULL);
+
+  self = g_object_new (GBP_TYPE_TESTUI_PANEL, NULL);
+  gbp_testui_panel_set_test_manager (self, test_manager);
+
+  return self;
 }
diff --git a/src/plugins/testui/gbp-testui-panel.h b/src/plugins/testui/gbp-testui-panel.h
index fe5391060..4e8f23797 100644
--- a/src/plugins/testui/gbp-testui-panel.h
+++ b/src/plugins/testui/gbp-testui-panel.h
@@ -20,6 +20,7 @@
 
 #pragma once
 
+#include <libide-foundry.h>
 #include <libide-gui.h>
 
 G_BEGIN_DECLS
@@ -28,6 +29,6 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbpTestuiPanel, gbp_testui_panel, GBP, TESTUI_PANEL, IdePane)
 
-GbpTestuiPanel *gbp_testui_panel_new (void);
+GbpTestuiPanel *gbp_testui_panel_new (IdeTestManager *test_manager);
 
 G_END_DECLS
diff --git a/src/plugins/testui/gbp-testui-panel.ui b/src/plugins/testui/gbp-testui-panel.ui
index 0af94c5f6..bdf6f8827 100644
--- a/src/plugins/testui/gbp-testui-panel.ui
+++ b/src/plugins/testui/gbp-testui-panel.ui
@@ -31,20 +31,18 @@
           <lookup name="item">GtkListItem</lookup>
         </binding>
         <binding name="icon-name">
-          <lookup name="icon-name" type="IdeTest">
-            <lookup name="item">GtkListItem</lookup>
+          <lookup name="icon-name" type="GbpTestuiItem">
+            <lookup name="item">expander</lookup>
           </lookup>
         </binding>
         <binding name="expanded-icon-name">
-          <!-- TODO: add expanded-icon-name -->
-          <lookup name="icon-name" type="IdeTest">
-            <lookup name="item">GtkListItem</lookup>
+          <lookup name="expanded-icon-name" type="GbpTestuiItem">
+            <lookup name="item">expander</lookup>
           </lookup>
         </binding>
         <binding name="title">
-          <!-- TODO: add expanded-icon-name -->
-          <lookup name="title" type="IdeTest">
-            <lookup name="item">GtkListItem</lookup>
+          <lookup name="title" type="GbpTestuiItem">
+            <lookup name="item">expander</lookup>
           </lookup>
         </binding>
       </object>
diff --git a/src/plugins/testui/gbp-testui-workspace-addin.c b/src/plugins/testui/gbp-testui-workspace-addin.c
index 151c1d99b..c8531e193 100644
--- a/src/plugins/testui/gbp-testui-workspace-addin.c
+++ b/src/plugins/testui/gbp-testui-workspace-addin.c
@@ -85,10 +85,7 @@ gbp_testui_workspace_addin_load (IdeWorkspaceAddin *addin,
   test_manager = ide_test_manager_from_context (context);
   pty = ide_test_manager_get_pty (test_manager);
 
-  self->panel = gbp_testui_panel_new ();
-  g_object_bind_property (test_manager, "model",
-                          self->panel, "model",
-                          G_BINDING_SYNC_CREATE);
+  self->panel = gbp_testui_panel_new (test_manager);
   g_signal_connect_object (self->panel,
                            "test-activated",
                            G_CALLBACK (on_test_activated_cb),
diff --git a/src/plugins/testui/meson.build b/src/plugins/testui/meson.build
index ee9e95f6a..c8229bf1f 100644
--- a/src/plugins/testui/meson.build
+++ b/src/plugins/testui/meson.build
@@ -1,8 +1,9 @@
 plugins_sources += files([
   'testui-plugin.c',
+  'gbp-testui-item.c',
   'gbp-testui-output-panel.c',
-  'gbp-testui-workspace-addin.c',
   'gbp-testui-panel.c',
+  'gbp-testui-workspace-addin.c',
 ])
 
 plugin_testui_resources = gnome.compile_resources(


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]