[glibmm] tests: Add glibmm_interface_move.



commit 9a81b80ec1952fa01f873af4d7273b7f834d3678
Author: Murray Cumming <murrayc murrayc com>
Date:   Sat Aug 22 21:36:20 2015 +0200

    tests: Add glibmm_interface_move.
    
    This code got unpleasantly big because I wanted to test a C++
    class that wraps a GObject while also implementing a C++ Interface
    that wraps a GInterface that the GObject implements. But it seems
    to work.
    
    However, the code to test a raw TestInterface is commented out
    because the move constructor does not pass the test. I am not sure
    if this should even be expected to work:
      Interface interface = std::move(object);
    or:
      Base base = std::move(derived);
    
    Surely that would lose the data (and virtual method table) from the
    Derived class anyway?

 tests/Makefile.am                   |    2 +
 tests/glibmm_interface_move/main.cc |  292 +++++++++++++++++++++++++++++++++++
 2 files changed, 294 insertions(+), 0 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 94d3d8c..e01f418 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -29,6 +29,7 @@ check_PROGRAMS =                              \
        glibmm_date/test                        \
        glibmm_buildfilename/test               \
        glibmm_interface_implementation/test    \
+       glibmm_interface_move/test                      \
        glibmm_mainloop/test                    \
        glibmm_nodetree/test                    \
        glibmm_object_move/test                 \
@@ -89,6 +90,7 @@ glibmm_date_test_SOURCES                 = glibmm_date/main.cc
 glibmm_interface_implementation_test_SOURCES = glibmm_interface_implementation/main.cc
 glibmm_interface_implementation_test_LDADD = $(giomm_ldadd)
 
+glibmm_interface_move_test_SOURCES       = glibmm_interface_move/main.cc
 glibmm_mainloop_test_SOURCES             = glibmm_mainloop/main.cc
 glibmm_nodetree_test_SOURCES             = glibmm_nodetree/main.cc
 glibmm_object_move_test_SOURCES          = glibmm_object_move/main.cc
diff --git a/tests/glibmm_interface_move/main.cc b/tests/glibmm_interface_move/main.cc
new file mode 100644
index 0000000..29662e9
--- /dev/null
+++ b/tests/glibmm_interface_move/main.cc
@@ -0,0 +1,292 @@
+#include <glibmm.h>
+#include <glibmm/private/interface_p.h>
+#include <glibmm/private/object_p.h>
+#include <iostream>
+#include <stdlib.h>
+
+//A basic derived GInterface, just to test Glib::Interface
+
+G_DECLARE_INTERFACE (TestIface, test_Iface, TEST, IFACE, GObject)
+
+struct _TestIface
+{
+  GTypeInterface g_iface;
+};
+
+static void
+test_Iface_init (gpointer)
+{}
+
+GType
+test_Iface_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      const GTypeInfo info =
+      {
+        sizeof (TestIface),  /* class_size */
+        test_Iface_init,           /* base_init */
+             0, 0, 0, 0, 0, 0, 0, 0
+      };
+
+      type = g_type_register_static (G_TYPE_INTERFACE, "TestIface",
+                                             &info, GTypeFlags(0));
+    }
+
+  return type;
+}
+
+#define TEST_TYPE_IFACE           (test_Iface_get_type               ())
+
+
+//A basic derived GObject, just to test Glib::Object.
+typedef struct {
+    GObject parent;
+} TestDerived;
+
+typedef struct {
+    GObjectClass parent;
+} TestDerivedClass;
+
+#define TEST_TYPE_DERIVED           (test_derived_get_type               ())
+#define TEST_DERIVED(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DERIVED, TestDerived))
+#define TEST_DERIVED_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST    ((cls), TEST_TYPE_DERIVED, TestDerivedClass))
+#define TEST_DERIVED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS  ((obj), TEST_TYPE_DERIVED, TestDerivedClass))
+
+static void test_derived_class_init (TestDerivedClass *)
+{}
+static void test_derived_init       (TestDerived *)
+{}
+
+G_DEFINE_TYPE_EXTENDED(TestDerived, test_derived, G_TYPE_OBJECT,
+  0, G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE,
+                            test_Iface_init))
+
+class TestInterface;
+
+class TestInterface_Class : public Glib::Interface_Class
+{
+public:
+  typedef TestInterface BaseClassType;
+
+  friend class TestInterface;
+
+  const Glib::Interface_Class& init()
+  {
+    if(!gtype_) // create the GType if necessary
+    {
+      // Glib::Interface_Class has to know the interface init function
+      // in order to add interfaces to implementing types.
+      class_init_func_ = &TestInterface_Class::iface_init_function;
+
+      // We can not derive from another interface, and it is not necessary anyway.
+      gtype_ = test_Iface_get_type();
+  }
+
+  return *this;
+  }
+
+  static void iface_init_function(void* /* g_iface */, void* /* iface_data */)
+  {
+  }
+
+  //static Glib::ObjectBase* wrap_new(GObject*);
+};
+
+class TestInterface : public Glib::Interface
+{
+protected:
+  typedef TestInterface_Class CppClassType;
+
+  TestInterface()
+  : Glib::Interface(derived_interface_class_.init())
+  {}
+
+public:
+  //A real application would never make the constructor public.
+  //It would instead have a protectd constructor and a public create() method.
+  TestInterface(GObject* gobject, int i)
+  : Glib::Interface(gobject),
+    i_(i)
+  {
+  }
+
+  static void add_interface(GType gtype_implementer)
+  {
+    derived_interface_class_.init().add_interface(gtype_implementer);
+  }
+
+  TestInterface(const TestInterface& src) = delete;
+  TestInterface& operator=(const TestInterface& src) = delete;
+
+  TestInterface(TestInterface&& src) noexcept
+  : Glib::Interface(std::move(src)),
+    i_(std::move(src.i_))
+  {}
+
+  TestInterface& operator=(TestInterface&& src) noexcept
+  {
+    Glib::Interface::operator=(std::move(src));
+    i_ = std::move(src.i_);
+
+    return *this;
+  }
+
+  int i_;
+
+private:
+  friend class TestInterface_Class;
+  static CppClassType derived_interface_class_;
+};
+
+class DerivedObject_Class : public Glib::Class
+{
+public:
+  typedef GObjectClass BaseClassType;
+  typedef Glib::Object_Class CppClassParent;
+
+  static void class_init_function(void* g_class, void* class_data)
+  {
+    const auto klass = static_cast<BaseClassType*>(g_class);
+    CppClassParent::class_init_function(klass, class_data);
+  }
+
+  const Glib::Class& init()
+  {
+    if(!gtype_) // create the GType if necessary
+    {
+      // Glib::Class has to know the class init function to clone custom types.
+      class_init_func_ = &DerivedObject_Class::class_init_function;
+
+      // This is actually just optimized away, apparently with no harm.
+      // Make sure that the parent type has been created.
+      //CppClassParent::CppObjectType::get_type();
+
+      // Create the wrapper type, with the same class/instance size as the base type.
+      register_derived_type(test_derived_get_type());
+
+      // Add derived versions of interfaces, if the C type implements any interfaces:
+      TestInterface::add_interface(get_type());
+    }
+
+    return *this;
+  }
+};
+
+TestInterface::CppClassType TestInterface::derived_interface_class_; // initialize static member
+
+class DerivedObject
+: public Glib::Object,
+  public TestInterface
+{
+public:
+  typedef DerivedObject_Class CppClassType;
+
+  //A real application would never make the constructor public.
+  //It would instead have a protected constructor and a public create() method.
+  DerivedObject(int i)
+  : Glib::ObjectBase(0),
+    Glib::Object(Glib::ConstructParams(derived_object_class_.init())),
+    i_(i)
+  {
+  }
+
+  DerivedObject(const DerivedObject& src) = delete;
+  DerivedObject& operator=(const DerivedObject& src) = delete;
+
+  DerivedObject(DerivedObject&& src) noexcept
+  : Glib::Object(std::move(src)),
+    TestInterface(std::move(src)),
+    i_(std::move(src.i_))
+  {}
+
+  DerivedObject& operator=(DerivedObject&& src) noexcept
+  {
+    Glib::Object::operator=(std::move(src));
+    TestInterface::operator=(std::move(src));
+    i_ = std::move(src.i_);
+
+    return *this;
+  }
+
+  int i_;
+
+private:
+  friend class DerivedObject_Class;
+  static CppClassType derived_object_class_;
+};
+
+DerivedObject::CppClassType DerivedObject::derived_object_class_; // initialize static member
+
+/* TODO: Shouldn't this work too?
+static
+void test_interface_move_constructor()
+{
+  GObject *gobject = G_OBJECT(g_object_new(TEST_TYPE_DERIVED, nullptr));
+  g_object_ref(gobject);
+
+  TestInterface derived(gobject, 5);
+  std::cout << "debug: gobj(): " << derived.gobj() << std::endl;
+  g_assert(derived.gobj() == gobject);
+  TestInterface derived2(std::move(derived));
+  g_assert_cmpint(derived2.i_, ==, 5);
+  std::cout << "debug: gobj(): " << derived2.gobj() << std::endl;
+  g_assert(derived2.gobj() == gobject);
+}
+
+static
+void test_interface_move_assignment_operator()
+{
+  GObject *gobject = G_OBJECT(g_object_new(TEST_TYPE_DERIVED, nullptr));
+  g_object_ref(gobject);
+
+  TestInterface derived(gobject, 5);
+  //std::cout << "debug: gobj(): " << derived.gobj() << std::endl;
+  g_assert(derived.gobj() == gobject);
+  TestInterface derived2 = std::move(derived);
+  g_assert_cmpint(derived2.i_, ==, 5);
+  //std::cout << "debug: gobj(): " << derived2.gobj() << std::endl;
+  g_assert(derived2.gobj() == gobject);
+}
+*/
+
+
+static
+void test_object_with_interface_move_constructor()
+{
+  DerivedObject derived(5);
+  g_assert_cmpint(derived.i_, ==, 5);
+  GObject *gobject = derived.gobj();
+  g_assert(derived.gobj() == gobject);
+  DerivedObject derived2(std::move(derived));
+  g_assert_cmpint(derived2.i_, ==, 5);
+  g_assert(derived2.gobj() == gobject);
+}
+
+static
+void test_object_with_interface_move_assignment_operator()
+{
+  DerivedObject derived(5);
+  g_assert_cmpint(derived.i_, ==, 5);
+  GObject *gobject = derived.gobj();
+  g_assert(derived.gobj() == gobject);
+  DerivedObject derived2 = std::move(derived);
+  g_assert_cmpint(derived2.i_, ==, 5);
+  g_assert(derived2.gobj() == gobject);
+}
+
+
+int main(int, char**)
+{
+  Glib::init();
+
+  //test_interface_move_constructor();
+  //test_interface_move_assignment_operator();
+
+  test_object_with_interface_move_constructor();
+  test_object_with_interface_move_assignment_operator();
+
+  return EXIT_SUCCESS;
+}


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