[Foxp][Test] simple echo test with custom payload size
[platform/upstream/dbus.git] / dbus / dbus-marshal-recursive-util.c
index e257a51..6d62983 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-marshal-recursive-util.c  Would be in dbus-marshal-recursive.c, but only used in bus/tests
  *
  * Copyright (C) 2004, 2005 Red Hat, Inc.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
+#include <config.h>
+
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
+
 #include "dbus-marshal-recursive.h"
 #include "dbus-marshal-basic.h"
+#include "dbus-signature.h"
 #include "dbus-internals.h"
+#include <string.h>
+
+static void
+basic_value_zero (DBusBasicValue *value)
+{
+
+#ifdef DBUS_HAVE_INT64
+  value->u64 = 0;
+#else
+  value->eight.first32 = 0;
+  value->eight.second32 = 0;
+#endif
+}
+
+static dbus_bool_t
+basic_value_equal (int             type,
+                   DBusBasicValue *lhs,
+                   DBusBasicValue *rhs)
+{
+  if (type == DBUS_TYPE_STRING ||
+      type == DBUS_TYPE_SIGNATURE ||
+      type == DBUS_TYPE_OBJECT_PATH)
+    {
+      return strcmp (lhs->str, rhs->str) == 0;
+    }
+  else
+    {
+#ifdef DBUS_HAVE_INT64
+      return lhs->u64 == rhs->u64;
+#else
+      return lhs->eight.first32 == rhs->eight.first32 &&
+        lhs->eight.second32 == rhs->eight.second32;
+#endif
+    }
+}
+
+static dbus_bool_t
+equal_values_helper (DBusTypeReader *lhs,
+                     DBusTypeReader *rhs)
+{
+  int lhs_type;
+  int rhs_type;
+
+  lhs_type = _dbus_type_reader_get_current_type (lhs);
+  rhs_type = _dbus_type_reader_get_current_type (rhs);
+
+  if (lhs_type != rhs_type)
+    return FALSE;
+
+  if (lhs_type == DBUS_TYPE_INVALID)
+    return TRUE;
+
+  if (dbus_type_is_basic (lhs_type))
+    {
+      DBusBasicValue lhs_value;
+      DBusBasicValue rhs_value;
+
+      basic_value_zero (&lhs_value);
+      basic_value_zero (&rhs_value);
+      
+      _dbus_type_reader_read_basic (lhs, &lhs_value);
+      _dbus_type_reader_read_basic (rhs, &rhs_value);
+
+      return basic_value_equal (lhs_type, &lhs_value, &rhs_value);
+    }
+  else
+    {
+      DBusTypeReader lhs_sub;
+      DBusTypeReader rhs_sub;
+
+      _dbus_type_reader_recurse (lhs, &lhs_sub);
+      _dbus_type_reader_recurse (rhs, &rhs_sub);
+
+      return equal_values_helper (&lhs_sub, &rhs_sub);
+    }
+}
+
+/**
+ * See whether the two readers point to identical data blocks.
+ *
+ * @param lhs reader 1
+ * @param rhs reader 2
+ * @returns #TRUE if the data blocks have the same values
+ */
+dbus_bool_t
+_dbus_type_reader_equal_values (const DBusTypeReader *lhs,
+                                const DBusTypeReader *rhs)
+{
+  DBusTypeReader copy_lhs = *lhs;
+  DBusTypeReader copy_rhs = *rhs;
+
+  return equal_values_helper (&copy_lhs, &copy_rhs);
+}
+
+/* TESTS */
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
 
-#ifdef DBUS_BUILD_TESTS
 #include "dbus-test.h"
 #include "dbus-list.h"
 #include <stdio.h>
@@ -299,6 +400,26 @@ struct TestTypeNodeContainerClass
  * and by merging read_value and set_value into one function
  * taking a flag argument.
  */
+static dbus_bool_t int16_write_value       (TestTypeNode   *node,
+                                            DataBlock      *block,
+                                            DBusTypeWriter *writer,
+                                            int             seed);
+static dbus_bool_t int16_read_value        (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            int             seed);
+static dbus_bool_t int16_set_value         (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            DBusTypeReader *realign_root,
+                                            int             seed);
+static dbus_bool_t int16_write_multi       (TestTypeNode   *node,
+                                            DataBlock      *block,
+                                            DBusTypeWriter *writer,
+                                            int             seed,
+                                            int             count);
+static dbus_bool_t int16_read_multi        (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            int             seed,
+                                            int             count);
 static dbus_bool_t int32_write_value       (TestTypeNode   *node,
                                             DataBlock      *block,
                                             DBusTypeWriter *writer,
@@ -409,6 +530,19 @@ static dbus_bool_t struct_set_value        (TestTypeNode   *node,
                                             int             seed);
 static dbus_bool_t struct_build_signature  (TestTypeNode   *node,
                                             DBusString     *str);
+static dbus_bool_t dict_write_value        (TestTypeNode   *node,
+                                            DataBlock      *block,
+                                            DBusTypeWriter *writer,
+                                            int             seed);
+static dbus_bool_t dict_read_value         (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            int             seed);
+static dbus_bool_t dict_set_value          (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            DBusTypeReader *realign_root,
+                                            int             seed);
+static dbus_bool_t dict_build_signature    (TestTypeNode   *node,
+                                            DBusString     *str);
 static dbus_bool_t array_write_value       (TestTypeNode   *node,
                                             DataBlock      *block,
                                             DBusTypeWriter *writer,
@@ -436,6 +570,35 @@ static dbus_bool_t variant_set_value       (TestTypeNode   *node,
 static void        container_destroy       (TestTypeNode   *node);
 
 
+
+static const TestTypeNodeClass int16_class = {
+  DBUS_TYPE_INT16,
+  sizeof (TestTypeNode),
+  0,
+  NULL,
+  NULL,
+  int16_write_value,
+  int16_read_value,
+  int16_set_value,
+  NULL,
+  int16_write_multi,
+  int16_read_multi
+};
+
+static const TestTypeNodeClass uint16_class = {
+  DBUS_TYPE_UINT16,
+  sizeof (TestTypeNode),
+  0,
+  NULL,
+  NULL,
+  int16_write_value, /* recycle from int16 */
+  int16_read_value,  /* recycle from int16 */
+  int16_set_value,   /* recycle from int16 */
+  NULL,
+  int16_write_multi, /* recycle from int16 */
+  int16_read_multi   /* recycle from int16 */
+};
+
 static const TestTypeNodeClass int32_class = {
   DBUS_TYPE_INT32,
   sizeof (TestTypeNode),
@@ -648,6 +811,20 @@ static const TestTypeNodeClass struct_2_class = {
   NULL
 };
 
+static const TestTypeNodeClass dict_1_class = {
+  DBUS_TYPE_ARRAY, /* this is correct, a dict is an array of dict entry */
+  sizeof (TestTypeNodeContainer),
+  1, /* number of entries */
+  NULL,
+  container_destroy,
+  dict_write_value,
+  dict_read_value,
+  dict_set_value,
+  dict_build_signature,
+  NULL,
+  NULL
+};
+
 static dbus_bool_t arrays_write_fixed_in_blocks = FALSE;
 
 static const TestTypeNodeClass array_0_class = {
@@ -722,6 +899,8 @@ static const TestTypeNodeClass variant_class = {
 
 static const TestTypeNodeClass* const
 basic_nodes[] = {
+  &int16_class,
+  &uint16_class,
   &int32_class,
   &uint32_class,
   &int64_class,
@@ -745,7 +924,8 @@ container_nodes[] = {
   &struct_2_class,
   &array_0_class,
   &array_2_class,
-  &variant_class
+  &variant_class,
+  &dict_1_class /* last since we want struct and array before it */
   /* array_9_class is omitted on purpose, it's too slow;
    * we only use it in one hardcoded test below
    */
@@ -768,7 +948,7 @@ node_new (const TestTypeNodeClass *klass)
       if (!(* klass->construct) (node))
         {
           dbus_free (node);
-          return FALSE;
+          return NULL;
         }
     }
 
@@ -806,23 +986,11 @@ node_read_value (TestTypeNode   *node,
                  DBusTypeReader *reader,
                  int             seed)
 {
-  DBusTypeMark mark;
-  DBusTypeReader restored;
-
-  _dbus_type_reader_save_mark (reader, &mark);
+  /* DBusTypeReader restored; */
 
   if (!(* node->klass->read_value) (node, reader, seed))
     return FALSE;
 
-  _dbus_type_reader_init_from_mark (&restored,
-                                    reader->byte_order,
-                                    reader->type_str,
-                                    reader->value_str,
-                                    &mark);
-
-  if (!(* node->klass->read_value) (node, &restored, seed))
-    return FALSE;
-
   return TRUE;
 }
 
@@ -922,7 +1090,7 @@ run_test_copy (NodeIterationData *nid)
   DBusTypeReader reader;
   DBusTypeWriter writer;
 
-  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("\n");
 
   src = nid->block;
 
@@ -985,7 +1153,7 @@ run_test_values_only_write (NodeIterationData *nid)
   dbus_bool_t retval;
   int sig_len;
 
-  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("\n");
 
   retval = FALSE;
 
@@ -1053,7 +1221,7 @@ run_test_set_values (NodeIterationData *nid)
   dbus_bool_t retval;
   int i;
 
-  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("\n");
 
   retval = FALSE;
 
@@ -1110,7 +1278,7 @@ run_test_delete_values (NodeIterationData *nid)
   dbus_bool_t retval;
   int t;
 
-  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("\n");
 
   retval = FALSE;
 
@@ -1425,6 +1593,87 @@ value_generator (int *ip)
 }
 
 static void
+build_body (TestTypeNode **nodes,
+            int            n_nodes,
+            int            byte_order,
+            DBusString    *signature,
+            DBusString    *body)
+{
+  int i;
+  DataBlock block;
+  DBusTypeReader reader;
+  DBusTypeWriter writer;
+
+  i = 0;
+  while (i < n_nodes)
+    {
+      if (! node_build_signature (nodes[i], signature))
+        _dbus_assert_not_reached ("no memory");
+      
+      ++i;
+    }
+
+  if (!data_block_init (&block, byte_order, 0))
+    _dbus_assert_not_reached ("no memory");
+  
+  data_block_init_reader_writer (&block,
+                                 &reader, &writer);
+  
+  /* DBusTypeWriter assumes it's writing into an existing signature,
+   * so doesn't add nul on its own. We have to do that.
+   */
+  if (!_dbus_string_insert_byte (&block.signature,
+                                 0, '\0'))
+    _dbus_assert_not_reached ("no memory");
+
+  i = 0;
+  while (i < n_nodes)
+    {
+      if (!node_write_value (nodes[i], &block, &writer, i))
+        _dbus_assert_not_reached ("no memory");
+
+      ++i;
+    }
+
+  if (!_dbus_string_copy_len (&block.body, 0,
+                              _dbus_string_get_length (&block.body) - N_FENCE_BYTES,
+                              body, 0))
+    _dbus_assert_not_reached ("oom");
+
+  data_block_free (&block);  
+}
+
+dbus_bool_t
+dbus_internal_do_not_use_generate_bodies (int           sequence,
+                                          int           byte_order,
+                                          DBusString   *signature,
+                                          DBusString   *body)
+{
+  TestTypeNode *nodes[1];
+  int i;
+  int n_nodes;
+
+  nodes[0] = value_generator (&sequence);
+
+  if (nodes[0] == NULL)
+    return FALSE;
+
+  n_nodes = 1;
+  
+  build_body (nodes, n_nodes, byte_order, signature, body);
+
+
+  i = 0;
+  while (i < n_nodes)
+    {
+      node_destroy (nodes[i]);
+      ++i;
+    }
+  
+  return TRUE;
+}
+
+static void
 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
                                       int                      n_nested)
 {
@@ -1675,6 +1924,14 @@ make_and_run_test_nodes (void)
     node_destroy (node);
   }
 
+  if (_dbus_getenv ("DBUS_TEST_SLOW") == NULL ||
+      atoi (_dbus_getenv ("DBUS_TEST_SLOW")) < 1)
+    {
+      fprintf (stderr, "skipping remaining marshal-recursive tests, "
+          "run with DBUS_TEST_SLOW=1 (or more) to enable\n");
+      goto out;
+    }
+
   start_next_test ("Each container of each container of each value %d iterations\n",
                    N_CONTAINERS * N_CONTAINERS * N_VALUES);
   for (i = 0; i < N_CONTAINERS; i++)
@@ -1747,8 +2004,15 @@ make_and_run_test_nodes (void)
       node_destroy (outer_container);
     }
 
-#if 0
-  /* This one takes a really long time, so comment it out for now */
+  /* This one takes a really long time (10 minutes on a Core2), so only enable
+   * it if you're really sure */
+  if (atoi (_dbus_getenv ("DBUS_TEST_SLOW")) < 2)
+    {
+      fprintf (stderr, "skipping really slow marshal-recursive test, "
+          "run with DBUS_TEST_SLOW=2 (or more) to enable\n");
+      goto out;
+    }
+
   start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
                    N_VALUES * N_VALUES * N_VALUES);
   {
@@ -1772,8 +2036,8 @@ make_and_run_test_nodes (void)
         node_destroy (nodes[0]);
       }
   }
-#endif /* #if 0 expensive test */
 
+out:
   fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
            n_iterations_completed_total);
   fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
@@ -1800,6 +2064,142 @@ _dbus_marshal_recursive_test (void)
  */
 #define MAX_MULTI_COUNT 5
 
+#define SAMPLE_INT16           1234
+#define SAMPLE_INT16_ALTERNATE 6785
+static dbus_int16_t
+int16_from_seed (int seed)
+{
+  /* Generate an integer value that's predictable from seed.  We could
+   * just use seed itself, but that would only ever touch one byte of
+   * the int so would miss some kinds of bug.
+   */
+  dbus_int16_t v;
+
+  v = 42; /* just to quiet compiler afaik */
+  switch (seed % 5)
+    {
+    case 0:
+      v = SAMPLE_INT16;
+      break;
+    case 1:
+      v = SAMPLE_INT16_ALTERNATE;
+      break;
+    case 2:
+      v = -1;
+      break;
+    case 3:
+      v = _DBUS_INT16_MAX;
+      break;
+    case 4:
+      v = 1;
+      break;
+    }
+
+  if (seed > 1)
+    v *= seed; /* wraps around eventually, which is fine */
+
+  return v;
+}
+
+static dbus_bool_t
+int16_write_value (TestTypeNode   *node,
+                   DataBlock      *block,
+                   DBusTypeWriter *writer,
+                   int             seed)
+{
+  /* also used for uint16 */
+  dbus_int16_t v;
+
+  v = int16_from_seed (seed);
+
+  return _dbus_type_writer_write_basic (writer,
+                                        node->klass->typecode,
+                                        &v);
+}
+
+static dbus_bool_t
+int16_read_value (TestTypeNode   *node,
+                  DBusTypeReader *reader,
+                  int             seed)
+{
+  /* also used for uint16 */
+  dbus_int16_t v;
+
+  check_expected_type (reader, node->klass->typecode);
+
+  _dbus_type_reader_read_basic (reader,
+                                (dbus_int16_t*) &v);
+
+  _dbus_assert (v == int16_from_seed (seed));
+
+  return TRUE;
+}
+
+static dbus_bool_t
+int16_set_value (TestTypeNode   *node,
+                 DBusTypeReader *reader,
+                 DBusTypeReader *realign_root,
+                 int             seed)
+{
+  /* also used for uint16 */
+  dbus_int16_t v;
+
+  v = int16_from_seed (seed);
+
+  return _dbus_type_reader_set_basic (reader,
+                                      &v,
+                                      realign_root);
+}
+
+static dbus_bool_t
+int16_write_multi (TestTypeNode   *node,
+                   DataBlock      *block,
+                   DBusTypeWriter *writer,
+                   int             seed,
+                   int             count)
+{
+  /* also used for uint16 */
+  dbus_int16_t values[MAX_MULTI_COUNT];
+  dbus_int16_t *v_ARRAY_INT16 = values;
+  int i;
+
+  for (i = 0; i < count; ++i)
+    values[i] = int16_from_seed (seed + i);
+
+  return _dbus_type_writer_write_fixed_multi (writer,
+                                              node->klass->typecode,
+                                              &v_ARRAY_INT16, count);
+}
+
+static dbus_bool_t
+int16_read_multi (TestTypeNode   *node,
+                  DBusTypeReader *reader,
+                  int             seed,
+                  int             count)
+{
+  /* also used for uint16 */
+  dbus_int16_t *values;
+  int n_elements;
+  int i;
+
+  check_expected_type (reader, node->klass->typecode);
+
+  _dbus_type_reader_read_fixed_multi (reader,
+                                      &values,
+                                      &n_elements);
+
+  if (n_elements != count)
+    _dbus_warn ("got %d elements expected %d\n", n_elements, count);
+  _dbus_assert (n_elements == count);
+
+  for (i = 0; i < count; i++)
+    _dbus_assert (((dbus_int16_t)_dbus_unpack_uint16 (reader->byte_order,
+                                                      (const unsigned char*)values + (i * 2))) ==
+                  int16_from_seed (seed + i));
+
+  return TRUE;
+}
+
 
 #define SAMPLE_INT32           12345678
 #define SAMPLE_INT32_ALTERNATE 53781429
@@ -2064,9 +2464,10 @@ string_write_value (TestTypeNode   *node,
                     DBusTypeWriter *writer,
                     int             seed)
 {
-  char buf[MAX_SAMPLE_STRING_LEN];
+  char buf[MAX_SAMPLE_STRING_LEN + 1]="";
   const char *v_string = buf;
 
+
   string_from_seed (buf, node->klass->subclass_detail,
                     seed);
 
@@ -2081,7 +2482,8 @@ string_read_value (TestTypeNode   *node,
                    int             seed)
 {
   const char *v;
-  char buf[MAX_SAMPLE_STRING_LEN];
+  char buf[MAX_SAMPLE_STRING_LEN + 1];
+  v = buf;
 
   check_expected_type (reader, node->klass->typecode);
 
@@ -2107,7 +2509,7 @@ string_set_value (TestTypeNode   *node,
                   DBusTypeReader *realign_root,
                   int             seed)
 {
-  char buf[MAX_SAMPLE_STRING_LEN];
+  char buf[MAX_SAMPLE_STRING_LEN + 1];
   const char *v_string = buf;
 
   string_from_seed (buf, node->klass->subclass_detail,
@@ -2264,8 +2666,8 @@ double_read_value (TestTypeNode   *node,
 
   if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
     {
-#ifdef DBUS_HAVE_INT64
-      _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
+#ifdef DBUS_INT64_PRINTF_MODIFIER
+      _dbus_warn ("Expected double %g got %g\n bits = 0x%" DBUS_INT64_PRINTF_MODIFIER "x vs.\n bits = 0x%" DBUS_INT64_PRINTF_MODIFIER "x)\n",
                   expected, v,
                   *(dbus_uint64_t*)(char*)&expected,
                   *(dbus_uint64_t*)(char*)&v);
@@ -2305,18 +2707,26 @@ object_path_from_seed (char *buf,
 
   v = (unsigned char) ('A' + seed);
 
-  i = 0;
-  while (i + 1 < len)
+  if (len < 2)
     {
-      if (v < 'A' || v > 'z')
-        v = 'A';
-
-      buf[i] = '/';
-      ++i;
-      buf[i] = v;
-      ++i;
+      buf[0] = '/';
+      i = 1;
+    }
+  else
+    {
+      i = 0;
+      while (i + 1 < len)
+        {
+          if (v < 'A' || v > 'z')
+            v = 'A';
 
-      v += 1;
+          buf[i] = '/';
+          ++i;
+          buf[i] = v;
+          ++i;
+          
+          v += 1;
+        }
     }
 
   buf[i] = '\0';
@@ -2328,7 +2738,7 @@ object_path_write_value (TestTypeNode   *node,
                          DBusTypeWriter *writer,
                          int             seed)
 {
-  char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
+  char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1];
   const char *v_string = buf;
 
   object_path_from_seed (buf, seed);
@@ -2344,7 +2754,7 @@ object_path_read_value (TestTypeNode   *node,
                         int             seed)
 {
   const char *v;
-  char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
+  char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1];
 
   check_expected_type (reader, node->klass->typecode);
 
@@ -2369,7 +2779,7 @@ object_path_set_value (TestTypeNode   *node,
                        DBusTypeReader *realign_root,
                        int             seed)
 {
-  char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
+  char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1];
   const char *v_string = buf;
 
   object_path_from_seed (buf, seed);
@@ -2384,8 +2794,6 @@ static void
 signature_from_seed (char *buf,
                      int   seed)
 {
-  int i;
-  const char *s;
   /* try to avoid ascending, descending, or alternating length to help find bugs */
   const char *sample_signatures[] = {
     "asax"
@@ -2396,13 +2804,7 @@ signature_from_seed (char *buf,
     "a(ii)"
   };
 
-  s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
-
-  for (i = 0; s[i]; i++)
-    {
-      buf[i] = s[i];
-    }
-  buf[i] = '\0';
+  strcpy (buf, sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)]);
 }
 
 static dbus_bool_t
@@ -2411,7 +2813,7 @@ signature_write_value (TestTypeNode   *node,
                        DBusTypeWriter *writer,
                        int             seed)
 {
-  char buf[MAX_SAMPLE_SIGNATURE_LEN];
+  char buf[MAX_SAMPLE_SIGNATURE_LEN + 1];
   const char *v_string = buf;
 
   signature_from_seed (buf, seed);
@@ -2427,7 +2829,7 @@ signature_read_value (TestTypeNode   *node,
                       int             seed)
 {
   const char *v;
-  char buf[MAX_SAMPLE_SIGNATURE_LEN];
+  char buf[MAX_SAMPLE_SIGNATURE_LEN + 1];
 
   check_expected_type (reader, node->klass->typecode);
 
@@ -2453,7 +2855,7 @@ signature_set_value (TestTypeNode   *node,
                      DBusTypeReader *realign_root,
                      int             seed)
 {
-  char buf[MAX_SAMPLE_SIGNATURE_LEN];
+  char buf[MAX_SAMPLE_SIGNATURE_LEN + 1];
   const char *v_string = buf;
 
   signature_from_seed (buf, seed);
@@ -2672,7 +3074,7 @@ array_write_value (TestTypeNode   *node,
     goto oom;
 
   if (arrays_write_fixed_in_blocks &&
-      _dbus_type_is_fixed (element_type) &&
+      dbus_type_is_fixed (element_type) &&
       child->klass->write_multi)
     {
       if (!node_write_multi (child, block, &sub, seed, n_copies))
@@ -2736,7 +3138,7 @@ array_read_or_set_value (TestTypeNode   *node,
       _dbus_type_reader_recurse (reader, &sub);
 
       if (realign_root == NULL && arrays_write_fixed_in_blocks &&
-          _dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) &&
+          dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) &&
           child->klass->read_multi)
         {
           if (!node_read_multi (child, &sub, seed, n_copies))
@@ -2926,6 +3328,230 @@ variant_set_value (TestTypeNode   *node,
   return variant_read_or_set_value (node, reader, realign_root, seed);
 }
 
+static dbus_bool_t
+dict_write_value (TestTypeNode   *node,
+                  DataBlock      *block,
+                  DBusTypeWriter *writer,
+                  int             seed)
+{
+  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
+  DataBlockState saved;
+  DBusTypeWriter sub;
+  DBusString entry_value_signature;
+  DBusString dict_entry_signature;
+  int i;
+  int n_entries;
+  TestTypeNode *child;
+
+  n_entries = node->klass->subclass_detail;
+
+  _dbus_assert (container->children != NULL);
+
+  data_block_save (block, &saved);
+
+  if (!_dbus_string_init (&entry_value_signature))
+    return FALSE;
+
+  if (!_dbus_string_init (&dict_entry_signature))
+    {
+      _dbus_string_free (&entry_value_signature);
+      return FALSE;
+    }
+  
+  child = _dbus_list_get_first (&container->children);
+
+  if (!node_build_signature (child,
+                             &entry_value_signature))
+    goto oom;
+
+  if (!_dbus_string_append (&dict_entry_signature,
+                            DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                            DBUS_TYPE_INT32_AS_STRING))
+    goto oom;
+
+  if (!_dbus_string_copy (&entry_value_signature, 0,
+                          &dict_entry_signature,
+                          _dbus_string_get_length (&dict_entry_signature)))
+    goto oom;
+
+  if (!_dbus_string_append_byte (&dict_entry_signature,
+                                 DBUS_DICT_ENTRY_END_CHAR))
+    goto oom;
+
+  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
+                                  &dict_entry_signature, 0,
+                                  &sub))
+    goto oom;
+
+  i = 0;
+  while (i < n_entries)
+    {
+      DBusTypeWriter entry_sub;
+      dbus_int32_t key;
+
+      if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_DICT_ENTRY,
+                                      NULL, 0,
+                                      &entry_sub))
+        goto oom;
+
+      key = int32_from_seed (seed + i);
+
+      if (!_dbus_type_writer_write_basic (&entry_sub,
+                                          DBUS_TYPE_INT32,
+                                          &key))
+        goto oom;
+      
+      if (!node_write_value (child, block, &entry_sub, seed + i))
+        goto oom;
+
+      if (!_dbus_type_writer_unrecurse (&sub, &entry_sub))
+        goto oom;
+      
+      ++i;
+    }
+
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    goto oom;
+  
+  _dbus_string_free (&entry_value_signature);
+  _dbus_string_free (&dict_entry_signature);
+  return TRUE;
+
+ oom:
+  data_block_restore (block, &saved);
+  _dbus_string_free (&entry_value_signature);
+  _dbus_string_free (&dict_entry_signature);
+  return FALSE;
+}
+
+static dbus_bool_t
+dict_read_or_set_value (TestTypeNode   *node,
+                        DBusTypeReader *reader,
+                        DBusTypeReader *realign_root,
+                        int             seed)
+{
+  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
+  DBusTypeReader sub;
+  int i;
+  int n_entries;
+  TestTypeNode *child;
+
+  n_entries = node->klass->subclass_detail;
+
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+
+  child = _dbus_list_get_first (&container->children);
+
+  if (n_entries > 0)
+    {
+      _dbus_type_reader_recurse (reader, &sub);
+
+      check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY);
+      
+      i = 0;
+      while (i < n_entries)
+        {
+          DBusTypeReader entry_sub;
+
+          check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY);
+          
+          _dbus_type_reader_recurse (&sub, &entry_sub);
+          
+          if (realign_root == NULL)
+            {
+              dbus_int32_t v;
+              
+              check_expected_type (&entry_sub, DBUS_TYPE_INT32);
+
+              _dbus_type_reader_read_basic (&entry_sub,
+                                            (dbus_int32_t*) &v);
+
+              _dbus_assert (v == int32_from_seed (seed + i));
+
+              NEXT_EXPECTING_TRUE (&entry_sub);
+              
+              if (!node_read_value (child, &entry_sub, seed + i))
+                return FALSE;
+
+              NEXT_EXPECTING_FALSE (&entry_sub);
+            }
+          else
+            {
+              dbus_int32_t v;
+              
+              v = int32_from_seed (seed + i);
+              
+              if (!_dbus_type_reader_set_basic (&entry_sub,
+                                                &v,
+                                                realign_root))
+                return FALSE;
+
+              NEXT_EXPECTING_TRUE (&entry_sub);
+              
+              if (!node_set_value (child, &entry_sub, realign_root, seed + i))
+                return FALSE;
+
+              NEXT_EXPECTING_FALSE (&entry_sub);
+            }
+          
+          if (i == (n_entries - 1))
+            NEXT_EXPECTING_FALSE (&sub);
+          else
+            NEXT_EXPECTING_TRUE (&sub);
+
+          ++i;
+        }
+    }
+
+  return TRUE;
+}
+
+static dbus_bool_t
+dict_read_value (TestTypeNode   *node,
+                 DBusTypeReader *reader,
+                 int             seed)
+{
+  return dict_read_or_set_value (node, reader, NULL, seed);
+}
+
+static dbus_bool_t
+dict_set_value (TestTypeNode   *node,
+                DBusTypeReader *reader,
+                DBusTypeReader *realign_root,
+                int             seed)
+{
+  return dict_read_or_set_value (node, reader, realign_root, seed);
+}
+
+static dbus_bool_t
+dict_build_signature (TestTypeNode   *node,
+                      DBusString     *str)
+{
+  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
+  int orig_len;
+
+  orig_len = _dbus_string_get_length (str);
+
+  if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
+    goto oom;
+
+  if (!_dbus_string_append (str, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING))
+    goto oom;
+  
+  if (!node_build_signature (_dbus_list_get_first (&container->children),
+                             str))
+    goto oom;
+
+  if (!_dbus_string_append_byte (str, DBUS_DICT_ENTRY_END_CHAR))
+    goto oom;
+
+  return TRUE;
+
+ oom:
+  _dbus_string_set_length (str, orig_len);
+  return FALSE;
+}
+
 static void
 container_destroy (TestTypeNode *node)
 {
@@ -2946,4 +3572,6 @@ container_destroy (TestTypeNode *node)
     }
 }
 
-#endif /* DBUS_BUILD_TESTS */
+#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
+
+#endif /* DBUS_ENABLE_EMBEDDED_TESTS */