[json-glib] gobject: Add experimental GBoxed<->JSON transformation



commit ff986ee5b8df45255f4f5ab01be0bbad893bc55e
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Oct 27 17:53:34 2009 +0000

    gobject: Add experimental GBoxed<->JSON transformation
    
    Serializing and deserializing GBoxed types is fairly complicated
    currently. If a GObject implements JsonSerializable it is possible
    for the class to intercept the JsonNode, parse it manually and
    then set the value to the property.
    
    This leaves a hole opened for:
    
      â?¢ manual (de)serialization of GBoxed types
      â?¢ (de)serialization of GBoxed properties in classes not
        implementing JsonSerializable
    
    In order to serialize and deserialize a GBoxed JSON-GLib should
    provide a mechanism similar to the GValue transformation functions:
    when registering the boxed type the developer should also be able
    to register a serialization and a deserialization functions pair
    matching the tuple:
    
      (GBoxed type, JSON type)
    
    The serialization function would be:
    
      JsonNode *(* JsonBoxedSerializeFunc) (gconstpointer boxed);
    
    And, conversely, the deserialization function would be:
    
      gpointer (* JsonBoxedDeserializeFunc) (JsonNode *node);
    
    Obviously, the whole machinery works only for GBoxed types that
    register the serialization and deserialization functions.

 .gitignore                   |   68 ++++++-----
 json-glib/json-gobject.c     |  264 +++++++++++++++++++++++++++++++++++++++++-
 json-glib/json-gobject.h     |   37 ++++++
 tests/Makefile.am            |    8 +-
 tests/test-serialize-boxed.c |  263 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 602 insertions(+), 38 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index caf3c70..4b93725 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ autom4te.cache
 !/build/autotools/shave.m4
 !/build/autotools/as-compiler-flag.m4
 !/build/autotools/introspection.m4
+compile
 configure
 config.guess
 config.h
@@ -16,7 +17,7 @@ config.log
 config.status
 config.sub
 depcomp
-doc/reference/version.xml
+/doc/reference/version.xml
 gtk-doc.make
 install-sh
 json-glib-1.0.pc
@@ -25,46 +26,47 @@ json-glib.pc
 .libs
 *.o
 *.lo
-json-enum-types.[ch]
-json-marshal.[ch]
-json-version.h
-Json-1.0.gir
-Json-1.0.typelib
-*.la
-stamp-enum-types
-stamp-marshal
-array-test
-object-test
-node-test
+/json-glib/json-enum-types.[ch]
+/json-glib/json-marshal.[ch]
+/json-glib/json-version.h
+/json-glib/Json-1.0.gir
+/json-glib/Json-1.0.typelib
+/json-glib/*.la
+/json-glib/stamp-enum-types
+/json-glib/stamp-marshal
+/json-glib/tests/array-test
+/json-glib/tests/object-test
+/json-glib/tests/node-test
 libtool
 ltmain.sh
 missing
 stamp-h1
 test-report.xml
 test-report.html
-test-parser
-test-generator
-test-serialize-simple
-test-serialize-complex
-test-serialize-full
+/tests/test-parser
+/tests/test-generator
+/tests/test-serialize-simple
+/tests/test-serialize-complex
+/tests/test-serialize-full
+/tests/test-serialize-boxed
 .*.swp
 *.stamp
-doc/reference/html
-doc/reference/tmpl
-doc/reference/xml
-doc/reference/json-glib-decl-list.txt
-doc/reference/json-glib-decl-list.txt.bak
-doc/reference/json-glib-decl.txt
-doc/reference/json-glib-decl.txt.bak
-doc/reference/json-glib-overrides.txt
-doc/reference/json-glib-undeclared.txt
-doc/reference/json-glib-undocumented.txt
-doc/reference/json-glib-unused.txt
-doc/reference/json-glib.args
-doc/reference/json-glib.hierarchy
-doc/reference/json-glib.interfaces
-doc/reference/json-glib.prerequisites
-doc/reference/json-glib.signals
+/doc/reference/html
+/doc/reference/tmpl
+/doc/reference/xml
+/doc/reference/json-glib-decl-list.txt
+/doc/reference/json-glib-decl-list.txt.bak
+/doc/reference/json-glib-decl.txt
+/doc/reference/json-glib-decl.txt.bak
+/doc/reference/json-glib-overrides.txt
+/doc/reference/json-glib-undeclared.txt
+/doc/reference/json-glib-undocumented.txt
+/doc/reference/json-glib-unused.txt
+/doc/reference/json-glib.args
+/doc/reference/json-glib.hierarchy
+/doc/reference/json-glib.interfaces
+/doc/reference/json-glib.prerequisites
+/doc/reference/json-glib.signals
 omf.make
 xmldocs.make
 /build/autotools/gtk-doc.m4
diff --git a/json-glib/json-gobject.c b/json-glib/json-gobject.c
index 2a8ec94..7c9a04d 100644
--- a/json-glib/json-gobject.c
+++ b/json-glib/json-gobject.c
@@ -45,6 +45,243 @@
 #include "json-parser.h"
 #include "json-generator.h"
 
+typedef struct _BoxedTransform  BoxedTransform;
+
+struct _BoxedTransform
+{
+  GType boxed_type;
+  gint node_type;
+
+  JsonBoxedSerializeFunc serialize;
+  JsonBoxedDeserializeFunc deserialize;
+};
+
+G_LOCK_DEFINE_STATIC (boxed_transforms);
+static GSList *boxed_transforms = NULL;
+
+static gint
+boxed_transforms_cmp (gconstpointer a,
+                      gconstpointer b)
+{
+  const BoxedTransform *ta = a;
+  const BoxedTransform *tb = b;
+
+  return tb->boxed_type - ta->boxed_type;
+}
+
+static gint
+boxed_transforms_find (gconstpointer a,
+                       gconstpointer b)
+{
+  const BoxedTransform *haystack = a;
+  const BoxedTransform *needle = b;
+
+  if (needle->node_type != -1)
+    return (haystack->boxed_type == needle->boxed_type &&
+            haystack->node_type == needle->node_type) ? 0 : 1;
+  else
+    return (haystack->boxed_type == needle->boxed_type) ? 0 : 1;
+}
+
+static BoxedTransform *
+lookup_boxed_transform (GType        gboxed_type,
+                        JsonNodeType node_type)
+{
+  BoxedTransform lookup;
+  GSList *t;
+
+  lookup.boxed_type = gboxed_type;
+  lookup.node_type = node_type;
+
+  t = g_slist_find_custom (boxed_transforms, &lookup, boxed_transforms_find);
+  if (t == NULL)
+    return NULL;
+
+  return t->data;
+}
+
+/**
+ * json_boxed_register_transform_func:
+ * @gboxed_type: a boxed type
+ * @node_type: a node type
+ * @serialize_func: (allow-none): serialization function for @boxed_type
+ *   into a #JsonNode of type @node_type; can be %NULL if @deserialize_func
+ *   is not %NULL
+ * @deserialize_func: (allow-none): deserialization function for @boxed_type
+ *   from a #JsonNode of type @node_type; can be %NULL if @serialize_func
+ *   is not %NULL
+ *
+ * Registers a serialization and deserialization functions for a #GBoxed
+ * of type @gboxed_type to and from a #JsonNode of type @node_type
+ *
+ * Since: 0.10
+ */
+void
+json_boxed_register_transform_func (GType                    gboxed_type,
+                                    JsonNodeType             node_type,
+                                    JsonBoxedSerializeFunc   serialize_func,
+                                    JsonBoxedDeserializeFunc deserialize_func)
+{
+  BoxedTransform *t;
+
+  g_return_if_fail (G_TYPE_IS_BOXED (gboxed_type));
+  g_return_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE);
+
+  if (serialize_func == NULL)
+    g_return_if_fail (deserialize_func != NULL);
+
+  if (deserialize_func == NULL)
+    g_return_if_fail (serialize_func != NULL);
+
+  G_LOCK (boxed_transforms);
+
+  t = lookup_boxed_transform (gboxed_type, node_type);
+  if (t == NULL)
+    {
+      t = g_slice_new (BoxedTransform);
+
+      t->boxed_type = gboxed_type;
+      t->node_type = node_type;
+      t->serialize = serialize_func;
+      t->deserialize = deserialize_func;
+
+      boxed_transforms = g_slist_insert_sorted (boxed_transforms, t,
+                                                boxed_transforms_cmp);
+    }
+  else
+    g_warning ("A transformation for the boxed type %s into "
+               "JSON nodes of type %s already exists",
+               g_type_name (gboxed_type),
+               json_node_type_get_name (node_type));
+
+  G_UNLOCK (boxed_transforms);
+}
+
+/**
+ * json_boxed_can_serialize:
+ * @gboxed_type: a boxed type
+ * @node_type: (out): the #JsonNode type to which the boxed type can be
+ *   deserialized into
+ *
+ * Checks whether it is possible to serialize a #GBoxed of
+ * type @gboxed_type into a #JsonNode of type @node_type
+ *
+ * Return value: %TRUE if the type can be serialized, %FALSE otherwise
+ *
+ * Since: 0.10
+ */
+gboolean
+json_boxed_can_serialize (GType         gboxed_type,
+                          JsonNodeType *node_type)
+{
+  BoxedTransform *t;
+
+  g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), FALSE);
+  g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, FALSE);
+
+  t = lookup_boxed_transform (gboxed_type, -1);
+  if (t != NULL && t->serialize != NULL)
+    {
+      if (node_type)
+        *node_type = t->node_type;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * json_boxed_can_deserialize:
+ * @gboxed_type: a boxed type
+ * @node_type: a #JsonNode type
+ *
+ * Checks whether it is possible to deserialize a #GBoxed of
+ * type @gboxed_type from a #JsonNode of type @node_type
+ *
+ * Return value: %TRUE if the type can be deserialized, %FALSE otherwise
+ *
+ * Since: 0.10
+ */
+gboolean
+json_boxed_can_deserialize (GType        gboxed_type,
+                            JsonNodeType node_type)
+{
+  BoxedTransform *t;
+
+  g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), FALSE);
+  g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, FALSE);
+
+  t = lookup_boxed_transform (gboxed_type, node_type);
+  if (t != NULL && t->deserialize != NULL)
+    return TRUE;
+
+  return FALSE;
+}
+
+/**
+ * json_boxed_serialize:
+ * @gboxed_type: a boxed type
+ * @node_type: a #JsonNode type
+ * @boxed: a pointer to a #GBoxed of type @gboxed_type
+ *
+ * Serializes @boxed, a pointer to a #GBoxed of type @gboxed_type,
+ * into a #JsonNode of type @node_type
+ *
+ * Return value: a #JsonNode with the serialization of the boxed
+ *   type, or %NULL if serialization either failed or was not
+ *   possible
+ *
+ * Since: 0.10
+ */
+JsonNode *
+json_boxed_serialize (GType          gboxed_type,
+                      JsonNodeType   node_type,
+                      gconstpointer  boxed)
+{
+  BoxedTransform *t;
+
+  g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), NULL);
+  g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, NULL);
+  g_return_val_if_fail (boxed != NULL, NULL);
+
+  t = lookup_boxed_transform (gboxed_type, node_type);
+  if (t != NULL && t->serialize != NULL)
+    return t->serialize (boxed);
+
+  return NULL;
+}
+
+/**
+ * json_boxed_serialize:
+ * @gboxed_type: a boxed type
+ * @node: a #JsonNode
+ *
+ * Deserializes @node into @boxed, a pointer to a #GBoxed of type
+ * @gboxed_type
+ *
+ * Since: 0.10
+ */
+gpointer
+json_boxed_deserialize (GType     gboxed_type,
+                        JsonNode *node)
+{
+  JsonNodeType node_type;
+  BoxedTransform *t;
+
+  g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), NULL);
+  g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, NULL);
+  g_return_val_if_fail (node != NULL, NULL);
+
+  node_type = json_node_get_node_type (node);
+
+  t = lookup_boxed_transform (gboxed_type, node_type);
+  if (t != NULL && t->deserialize != NULL)
+    return t->deserialize (node);
+
+  return NULL;
+}
+
 /* forward declaration */
 static JsonNode *json_serialize_pspec   (const GValue *real_value,
                                          GParamSpec   *pspec);
@@ -396,6 +633,21 @@ json_deserialize_pspec (GValue     *value,
   GValue node_value = { 0, };
   gboolean retval = FALSE;
 
+  if (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)) == G_TYPE_BOXED)
+    {
+      JsonNodeType node_type = json_node_get_node_type (node);
+      GType boxed_type = G_VALUE_TYPE (value);
+
+      if (json_boxed_can_deserialize (boxed_type, node_type))
+        {
+          gpointer boxed = json_boxed_deserialize (boxed_type, node);
+
+          g_value_take_boxed (value, boxed);
+
+          return TRUE;
+        }
+    }
+
   switch (JSON_NODE_TYPE (node))
     {
     case JSON_NODE_OBJECT:
@@ -554,6 +806,7 @@ json_serialize_pspec (const GValue *real_value,
 {
   JsonNode *retval = NULL;
   GValue value = { 0, };
+  JsonNodeType node_type;
 
   switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (real_value)))
     {
@@ -611,10 +864,17 @@ json_serialize_pspec (const GValue *real_value,
           retval = json_node_new (JSON_NODE_ARRAY);
           json_node_take_array (retval, array);
         }
-      else
+      else if (json_boxed_can_serialize (G_VALUE_TYPE (real_value), &node_type))
         {
-          g_warning ("Unsupported type `%s'", g_type_name (G_VALUE_TYPE (real_value)));
+          gpointer boxed = g_value_get_boxed (real_value);
+
+          retval = json_boxed_serialize (G_VALUE_TYPE (real_value),
+                                         node_type,
+                                         boxed);
         }
+      else
+        g_warning ("Boxed type '%s' is not handled by JSON-GLib",
+                   g_type_name (G_VALUE_TYPE (real_value)));
       break;
 
     case G_TYPE_UINT:
diff --git a/json-glib/json-gobject.h b/json-glib/json-gobject.h
index 8eacc58..207db52 100644
--- a/json-glib/json-gobject.h
+++ b/json-glib/json-gobject.h
@@ -79,6 +79,43 @@ gboolean  json_serializable_deserialize_property (JsonSerializable *serializable
                                                   GParamSpec       *pspec,
                                                   JsonNode         *property_node);
 
+/**
+ * JsonBoxedSerializeFunc:
+ * @boxed: a #GBoxed
+ *
+ * Serializes the passed #GBoxed and stores it inside a #JsonNode
+ *
+ * Return value: the newly created #JsonNode
+ *
+ * Since: 0.10
+ */
+typedef JsonNode *(* JsonBoxedSerializeFunc) (gconstpointer boxed);
+
+/**
+ * JsonBoxedDeserializeFunc:
+ * @node: a #JsonNode
+ *
+ * Deserializes the contents of the passed #JsonNode into a #GBoxed
+ *
+ * Return value: the newly created boxed type
+ *
+ * Since: 0.10
+ */
+typedef gpointer (* JsonBoxedDeserializeFunc) (JsonNode *node);
+
+void      json_boxed_register_transform_func (GType                     gboxed_type,
+                                              JsonNodeType              node_type,
+                                              JsonBoxedSerializeFunc    serialize_func,
+                                              JsonBoxedDeserializeFunc  deserialize_func);
+gboolean  json_boxed_can_serialize           (GType                     gboxed_type,
+                                              JsonNodeType             *node_type);
+gboolean  json_boxed_can_deserialize         (GType                     gboxed_type,
+                                              JsonNodeType              node_type);
+JsonNode *json_boxed_serialize               (GType                     gboxed_type,
+                                              JsonNodeType              node_type,
+                                              gconstpointer             boxed);
+gpointer  json_boxed_deserialize             (GType                     gboxed_type,
+                                              JsonNode                 *node);
 
 GObject *json_construct_gobject (GType         gtype,
                                  const gchar  *data,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 87f24ac..8209aa9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,9 +6,7 @@ NULL =
 noinst_PROGRAMS = $(TEST_PROGS)
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/json-glib
-AM_CFLAGS = -g $(JSON_CFLAGS)
-AM_CPPFLAGS = $(JSON_DEBUG_CFLAGS)
-
+AM_CPPFLAGS = $(JSON_DEBUG_CFLAGS) $(JSON_CFLAGS) $(MAINTAINER_CFLAGS)
 progs_ldadd = $(top_builddir)/json-glib/libjson-glib-1.0.la $(JSON_LIBS)
 
 TESTS_ENVIRONMENT = srcdir=$(srcdir)
@@ -29,6 +27,10 @@ TEST_PROGS                     += test-serialize-complex
 test_serialize_complex_SOURCES  = test-serialize-complex.c
 test_serialize_complex_LDADD    = $(progs_ldadd)
 
+TEST_PROGS                   += test-serialize-boxed
+test_serialize_boxed_SOURCES  = test-serialize-boxed.c
+test_serialize_boxed_LDADD    = $(progs_ldadd)
+
 TEST_PROGS                  += test-serialize-full
 test_serialize_full_SOURCES  = test-serialize-full.c
 test_serialize_full_LDADD    = $(progs_ldadd)
diff --git a/tests/test-serialize-boxed.c b/tests/test-serialize-boxed.c
new file mode 100644
index 0000000..d96acfd
--- /dev/null
+++ b/tests/test-serialize-boxed.c
@@ -0,0 +1,263 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib-object.h>
+
+#include <json-glib/json-glib.h>
+#include <json-glib/json-gobject.h>
+
+#define TEST_TYPE_BOXED                 (test_boxed_get_type ())
+#define TEST_TYPE_OBJECT                (test_object_get_type ())
+#define TEST_OBJECT(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_OBJECT, TestObject))
+#define TEST_IS_OBJECT(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_OBJECT))
+#define TEST_OBJECT_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass))
+#define TEST_IS_OBJECT_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT))
+#define TEST_OBJECT_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJECT, TestObjectClass))
+
+typedef struct _TestBoxed               TestBoxed;
+typedef struct _TestObject              TestObject;
+typedef struct _TestObjectClass         TestObjectClass;
+
+struct _TestBoxed
+{
+  gint foo;
+  gboolean bar;
+};
+
+struct _TestObject
+{
+  GObject parent_instance;
+
+  TestBoxed blah;
+};
+
+struct _TestObjectClass
+{
+  GObjectClass parent_class;
+};
+
+GType test_object_get_type (void);
+
+/*** implementation ***/
+
+static gpointer
+test_boxed_copy (gpointer src)
+{
+  return g_slice_dup (TestBoxed, src);
+}
+
+static void
+test_boxed_free (gpointer boxed)
+{
+  if (G_LIKELY (boxed != NULL))
+    g_slice_free (TestBoxed, boxed);
+}
+
+static JsonNode *
+test_boxed_serialize (gconstpointer boxed)
+{
+  const TestBoxed *test = boxed;
+  JsonObject *object;
+  JsonNode *node;
+
+  if (boxed == NULL)
+    return json_node_new (JSON_NODE_NULL);
+
+  object = json_object_new ();
+  node = json_node_new (JSON_NODE_OBJECT);
+
+  json_object_set_int_member (object, "foo", test->foo);
+  json_object_set_boolean_member (object, "bar", test->bar);
+
+  json_node_take_object (node, object);
+
+  if (g_test_verbose ())
+    {
+      g_print ("Serialize: { foo: %" G_GINT64_FORMAT ", bar: %s }\n",
+               json_object_get_int_member (object, "foo"),
+               json_object_get_boolean_member (object, "bar") ? "true" : "false");
+    }
+
+  return node;
+}
+
+static gpointer
+test_boxed_deserialize (JsonNode *node)
+{
+  JsonObject *object;
+  TestBoxed *test;
+
+  if (json_node_get_node_type (node) != JSON_NODE_OBJECT)
+    return NULL;
+
+  object = json_node_get_object (node);
+
+  test = g_slice_new (TestBoxed);
+  test->foo = json_object_get_int_member (object, "foo");
+  test->bar = json_object_get_boolean_member (object, "bar");
+
+  if (g_test_verbose ())
+    {
+      g_print ("Deserialize: { foo: %d, bar: %s }\n",
+               test->foo,
+               test->bar ? "true" : "false");
+    }
+
+  return test;
+}
+
+GType
+test_boxed_get_type (void)
+{
+  static GType b_type = 0;
+
+  if (G_UNLIKELY (b_type == 0))
+    {
+      b_type = g_boxed_type_register_static ("TestBoxed",
+                                             test_boxed_copy,
+                                             test_boxed_free);
+
+      if (g_test_verbose ())
+        g_print ("Registering transform functions\n");
+
+      json_boxed_register_transform_func (b_type, JSON_NODE_OBJECT,
+                                          test_boxed_serialize,
+                                          test_boxed_deserialize);
+    }
+
+  return b_type;
+}
+
+enum
+{
+  PROP_0,
+
+  PROP_BLAH
+};
+
+G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT);
+
+static void
+test_object_finalize (GObject *gobject)
+{
+  G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
+}
+
+static void
+test_object_set_property (GObject      *gobject,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_BLAH:
+      {
+        const TestBoxed *blah = g_value_get_boxed (value);
+
+        TEST_OBJECT (gobject)->blah = *blah;
+      }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+test_object_get_property (GObject    *gobject,
+                          guint       prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_BLAH:
+      g_value_set_boxed (value, &(TEST_OBJECT (gobject)->blah));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+test_object_class_init (TestObjectClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = test_object_set_property;
+  gobject_class->get_property = test_object_get_property;
+  gobject_class->finalize = test_object_finalize;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BLAH,
+                                   g_param_spec_boxed ("blah", "Blah", "Blah",
+                                                       TEST_TYPE_BOXED,
+                                                       G_PARAM_READWRITE));
+}
+
+static void
+test_object_init (TestObject *object)
+{
+  object->blah.foo = 0;
+  object->blah.bar = FALSE;
+}
+
+static const gchar *serialize_data =
+"{\n"
+"  \"blah\" : {\n"
+"    \"foo\" : 42,\n"
+"    \"bar\" : true\n"
+"  }\n"
+"}";
+
+static void
+test_serialize_boxed (void)
+{
+  TestBoxed boxed = { 42, TRUE };
+  GObject *obj;
+  gchar *data;
+  gsize len;
+
+  obj = g_object_new (TEST_TYPE_OBJECT, "blah", &boxed, NULL);
+
+  data = json_serialize_gobject (obj, &len);
+
+  g_assert_cmpint (len, ==, strlen (serialize_data));
+  g_assert_cmpstr (data, ==, serialize_data);
+
+  if (g_test_verbose ())
+    g_print ("TestObject:\n%s\n", data);
+
+  g_free (data);
+  g_object_unref (obj);
+}
+
+static void
+test_deserialize_boxed (void)
+{
+
+  GObject *obj;
+
+  obj = json_construct_gobject (TEST_TYPE_OBJECT, serialize_data, -1, NULL);
+  g_assert (TEST_IS_OBJECT (obj));
+  g_assert_cmpint (TEST_OBJECT (obj)->blah.foo, ==, 42);
+  g_assert (TEST_OBJECT (obj)->blah.bar);
+
+  g_object_unref (obj);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  g_type_init ();
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/boxed/serialize-property", test_serialize_boxed);
+  g_test_add_func ("/boxed/deserialize-property", test_deserialize_boxed);
+
+  return g_test_run ();
+}



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