Index: b/tests/test-ber-visitor.c
===================================================================
--- /dev/null
+++ b/tests/test-ber-visitor.c
@@ -0,0 +1,518 @@
+/*
+ * BER Output Visitor unit-tests.
+ *
+ * Copyright (C) 2011 Red Hat Inc.
+ * Copyright (C) 2011 IBM Corporation
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *  Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#include "qemu-common.h"
+#include "ber/ber-output-visitor.h"
+#include "ber/ber-input-visitor.h"
+#include "hw/hw.h"
+#include "include/qapi/visitor.h"
+
+
+typedef struct TestInputOutputVisitorData {
+    QEMUFile *qoutfile;
+    BEROutputVisitor *bov;
+    Visitor *ov;
+
+    QEMUFile *qinfile;
+    BERInputVisitor *biv;
+    Visitor *iv;
+} TestInputOutputVisitor;
+
+static void visitor_output_setup(TestInputOutputVisitor *data,
+                                 BERTypePC ber_type_pc)
+{
+    data->qoutfile = qemu_bufopen("w", NULL);
+
+    data->bov = ber_output_visitor_new(data->qoutfile, ber_type_pc);
+    g_assert(data->bov != NULL);
+
+    data->ov = ber_output_get_visitor(data->bov);
+    g_assert(data->ov != NULL);
+}
+
+static void visitor_output_setup_primitive(TestInputOutputVisitor *data,
+                                           const void *unused)
+{
+    visitor_output_setup(data, BER_TYPE_PRIMITIVE);
+}
+
+static void visitor_output_setup_constructed(TestInputOutputVisitor *data,
+                                             const void *unused)
+{
+    visitor_output_setup(data, BER_TYPE_CONSTRUCTED);
+}
+
+static void visitor_input_setup(TestInputOutputVisitor *data)
+{
+    const QEMUSizedBuffer *qsb = qemu_buf_get(data->qoutfile);
+    QEMUSizedBuffer *new_qsb = qsb_clone(qsb);
+    g_assert(new_qsb != NULL);
+
+    data->qinfile = qemu_bufopen("r", new_qsb);
+    g_assert(data->qinfile != NULL);
+
+    data->biv = ber_input_visitor_new(data->qinfile, ~0);
+    g_assert(data->biv != NULL);
+
+    data->iv = ber_input_get_visitor(data->biv);
+    g_assert(data->iv != NULL);
+}
+
+static void visitor_output_teardown(TestInputOutputVisitor *data,
+                                    const void *unused)
+{
+    ber_output_visitor_cleanup(data->bov);
+    data->bov = NULL;
+    data->ov = NULL;
+
+    ber_input_visitor_cleanup(data->biv);
+    data->biv = NULL;
+    data->iv = NULL;
+
+    if (data->qinfile) {
+        qemu_fclose(data->qinfile);
+    }
+    if (data->qoutfile) {
+        qemu_fclose(data->qoutfile);
+    }
+}
+
+static void test_visitor_out_int(TestInputOutputVisitor *data,
+                                 const void *unused)
+{
+    int64_t value_in = -42, value_out = 0;
+    Error *errp = NULL;
+
+    visit_type_int(data->ov, &value_in, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    visitor_input_setup(data);
+
+    visit_type_int(data->iv, &value_out, NULL, &errp);
+    g_assert_cmpint(value_out, ==, -42);
+}
+
+static void test_visitor_out_bool(TestInputOutputVisitor *data,
+                                  const void *unused)
+{
+    Error *errp = NULL;
+    bool value_in = true, value_out = false;
+
+    visit_type_bool(data->ov, &value_in, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    visitor_input_setup(data);
+
+    visit_type_bool(data->iv, &value_out, NULL, &errp);
+    g_assert_cmpint(value_out, ==, true);
+
+}
+
+static void test_visitor_out_string(TestInputOutputVisitor *data,
+                                    const void *unused)
+{
+    char *string_in = (char *) "Q E M U", *string_out = NULL;
+    Error *errp = NULL;
+
+    visit_type_str(data->ov, &string_in, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    visitor_input_setup(data);
+
+    visit_type_str(data->iv, &string_out, NULL, &errp);
+
+    g_assert_cmpstr(string_out, ==, string_in);
+    g_free(string_out);
+}
+
+static void test_visitor_out_no_string(TestInputOutputVisitor *data,
+                                       const void *unused)
+{
+    char *string_in = NULL, *string_out = NULL;
+    Error *errp = NULL;
+
+    /* A null string should return "" */
+    visit_type_str(data->ov, &string_in, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+    g_assert(qsb_get_length(qemu_buf_get(data->qoutfile)) == 2);
+
+    visitor_input_setup(data);
+
+    visit_type_str(data->iv, &string_out, NULL, &errp);
+    g_assert_cmpstr(string_out, ==, "");
+
+    g_free(string_out);
+}
+
+typedef struct SimpleStruct {
+    int64_t integer;
+    bool boolean;
+    char *string;
+} SimpleStruct;
+
+static void visit_type_SimpleStruct(Visitor *v, SimpleStruct **obj,
+                                    const char *name, Error **errp)
+{
+    visit_start_struct(v, (void **)obj, "SimpleStruct", name,
+                       sizeof(SimpleStruct), errp);
+
+    visit_type_int(v, &(*obj)->integer, "integer", errp);
+    visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+    visit_type_str(v, &(*obj)->string, "string", errp);
+
+    visit_end_struct(v, errp);
+}
+
+static void test_visitor_out_struct(TestInputOutputVisitor *data,
+                                    const void *unused)
+{
+    SimpleStruct test_struct = {
+        .integer = 42,
+        .boolean = false,
+        .string = (char *)"foo"
+    };
+    SimpleStruct *p_in = &test_struct, *p_out = NULL;
+    Error *errp = NULL;
+
+    visit_type_SimpleStruct(data->ov, &p_in, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+
+    visitor_input_setup(data);
+
+    visit_type_SimpleStruct(data->iv, &p_out, NULL, &errp);
+
+    g_assert_cmpint(p_out->integer, ==, 42);
+    g_assert_cmpint(p_out->boolean, ==, 0);
+    g_assert_cmpstr(p_out->string, ==, "foo");
+
+    g_free(p_out->string);
+    g_free(p_out);
+}
+
+static void visit_type_SimpleStructArray(Visitor *v, SimpleStruct **obj,
+                                         const char *name,
+                                         size_t elem_count, size_t elem_size,
+                                         Error **errp)
+{
+    size_t i;
+
+    visit_start_array(v, (void **)obj, name, elem_count, elem_size, errp);
+
+    for (i = 0; i < elem_count; i++) {
+        SimpleStruct *s = &((*obj)[i]);
+        visit_type_SimpleStruct(v, &s, "SimpleStruct", errp);
+        visit_next_array(v, errp);
+    }
+
+    visit_end_array(v, errp);
+}
+
+static void test_visitor_out_array(TestInputOutputVisitor *data,
+                                   const void *unused)
+{
+    SimpleStruct test_struct[] = {
+        {
+            .integer = 42,
+            .boolean = false,
+            .string = (char *)"foo"
+        }, {
+            .integer = 1000,
+            .boolean = true,
+            .string = (char *)"bar"
+        }
+    };
+    SimpleStruct *p_in = test_struct, *p_out = NULL;
+    Error *errp = NULL;
+
+    visit_type_SimpleStructArray(data->ov, &p_in, NULL,
+                                 ARRAY_SIZE(test_struct),
+                                 sizeof(test_struct[0]), &errp);
+    g_assert(!error_is_set(&errp));
+
+    visitor_input_setup(data);
+
+    visit_type_SimpleStructArray(data->iv, &p_out, NULL,
+                                 ARRAY_SIZE(test_struct),
+                                 sizeof(test_struct[0]), &errp);
+
+    g_assert_cmpint(p_out[0].integer, ==, 42);
+    g_assert_cmpint(p_out[0].boolean, ==, 0);
+    g_assert_cmpstr(p_out[0].string, ==, "foo");
+
+    g_assert_cmpint(p_out[1].integer, ==, 1000);
+    g_assert_cmpint(p_out[1].boolean, ==, 1);
+    g_assert_cmpstr(p_out[1].string, ==, "bar");
+
+    g_free(p_out[0].string);
+    g_free(p_out[1].string);
+    g_free(p_out);
+}
+
+typedef struct NestedStruct {
+    int64_t integer;
+    bool boolean;
+    SimpleStruct simpleStruct[2];
+    char *string;
+} NestedStruct;
+
+static void visit_type_NestedStruct(Visitor *v, NestedStruct **obj,
+                                    const char *name, Error **errp)
+{
+    unsigned int i;
+
+    visit_start_struct(v, (void **)obj, "NestedStruct", name,
+                       sizeof(NestedStruct), errp);
+
+    visit_type_int(v, &(*obj)->integer, "integer", errp);
+    visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+
+    for (i = 0; i < ARRAY_SIZE((*obj)->simpleStruct); i++) {
+        SimpleStruct *simple = &(*obj)->simpleStruct[i];
+        visit_type_SimpleStruct(v, &simple, "SimpleStruct", errp);
+    }
+
+    visit_type_str(v, &(*obj)->string, "string", errp);
+
+    visit_end_struct(v, errp);
+}
+
+static void test_visitor_out_nested_struct(TestInputOutputVisitor *data,
+                                           const void *unused)
+{
+    NestedStruct nested_struct = {
+        .integer = 42,
+        .boolean = true,
+        .simpleStruct = {
+            {
+                .integer = 1000,
+                .boolean = false,
+                .string = (char *)"Hello",
+            }, {
+                .integer = 2000,
+                .boolean = false,
+                .string = (char *)"world!",
+            },
+        },
+        .string = (char *)"bar",
+    };
+    NestedStruct *p_in = &nested_struct, *p_out = NULL;
+    Error *errp = NULL;
+    unsigned int i;
+
+    visit_type_NestedStruct(data->ov, &p_in, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+
+    visitor_input_setup(data);
+
+    visit_type_NestedStruct(data->iv, &p_out, NULL, &errp);
+
+    g_assert_cmpint(p_out->integer, ==, 42);
+    g_assert_cmpint(p_out->boolean, ==, true);
+
+    g_assert_cmpint(p_out->simpleStruct[0].integer, ==, 1000);
+    g_assert_cmpint(p_out->simpleStruct[0].boolean, ==, 0);
+    g_assert_cmpstr(p_out->simpleStruct[0].string , ==, "Hello");
+
+    g_assert_cmpint(p_out->simpleStruct[1].integer, ==, 2000);
+    g_assert_cmpint(p_out->simpleStruct[1].boolean, ==, 0);
+    g_assert_cmpstr(p_out->simpleStruct[1].string , ==, "world!");
+
+    g_assert_cmpstr(p_out->string, ==, "bar");
+
+    g_free(p_out->string);
+    for (i = 0; i < ARRAY_SIZE(p_out->simpleStruct); i++) {
+        g_free(p_out->simpleStruct[i].string);
+    }
+    g_free(p_out);
+}
+
+typedef struct SimpleStringList {
+    char *value;
+    struct SimpleStringList *next;
+} SimpleStringList;
+
+static void visit_type_SimpleStringList(Visitor *m, SimpleStringList ** obj,
+                                  const char *name, Error **errp)
+{
+    GenericList *i, **head = (GenericList **)obj;
+
+    visit_start_list(m, name, errp);
+
+    for (*head = i = visit_next_list(m, head, errp);
+         i;
+         i = visit_next_list(m, &i, errp)) {
+        SimpleStringList *native_i = (SimpleStringList *)i;
+        visit_type_str(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+
+static void test_visitor_out_list(TestInputOutputVisitor *data,
+                                  const void *unused)
+{
+    SimpleStringList test_list = {
+        .value = (char *)"hello",
+        .next = &(SimpleStringList) {
+            .value = (char *)"world",
+            .next = NULL,
+        },
+    };
+    SimpleStringList *p_in = &test_list, *p_out = NULL, *iter = NULL, *_iter;
+    Error *errp = NULL;
+
+    visit_type_SimpleStringList(data->ov, &p_in, "SimpleStringList", &errp);
+    g_assert(!error_is_set(&errp));
+
+    visitor_input_setup(data);
+
+    visit_type_SimpleStringList(data->iv, &p_out, "SimpleStringList", &errp);
+    g_assert(!error_is_set(&errp));
+
+    iter = p_out;
+    g_assert_cmpstr(iter->value, ==, "hello");
+    iter = iter->next;
+    g_assert_cmpstr(iter->value, ==, "world");
+
+    for (iter = p_out; iter; iter = _iter) {
+        _iter = iter->next;
+        g_free(iter->value);
+        g_free(iter);
+    }
+}
+
+typedef struct SimpleStructList {
+    SimpleStruct *value;
+    struct SimpleStructList *next;
+} SimpleStructList;
+
+static void visit_type_SimpleStructList(Visitor *m, SimpleStructList ** obj,
+                                        const char *name, Error **errp)
+{
+    GenericList *i, **head = (GenericList **)obj;
+
+    visit_start_list(m, name, errp);
+
+    for (*head = i = visit_next_list(m, head, errp);
+         i;
+         i = visit_next_list(m, &i, errp)) {
+        SimpleStructList *native_i = (SimpleStructList *)i;
+        visit_type_SimpleStruct(m, &native_i->value, NULL, errp);
+    }
+
+    visit_end_list(m, errp);
+}
+
+static void test_visitor_out_simplestruct_list(TestInputOutputVisitor *data,
+                                               const void *unused)
+{
+    SimpleStructList test_list = {
+        .value = &(SimpleStruct) {
+            .string = (char *)"hello",
+            .integer = 1000,
+            .boolean = false,
+        },
+        .next = &(SimpleStructList) {
+            .value = &(SimpleStruct) {
+                .string = (char *)"world",
+                .integer = 2000,
+                .boolean = true,
+            },
+            .next = NULL,
+        },
+    };
+    SimpleStructList *p_in = &test_list, *p_out = NULL, *iter = NULL, *_iter;
+    Error *errp = NULL;
+
+    visit_type_SimpleStructList(data->ov, &p_in, "SimpleStructList", &errp);
+    g_assert(!error_is_set(&errp));
+
+    visitor_input_setup(data);
+
+    visit_type_SimpleStructList(data->iv, &p_out, "SimpleStructList", &errp);
+    g_assert(!error_is_set(&errp));
+
+    iter = p_out;
+    g_assert_cmpstr(iter->value->string, ==, "hello");
+    iter = iter->next;
+    g_assert_cmpstr(iter->value->string, ==, "world");
+
+    for (iter = p_out; iter; iter = _iter) {
+        _iter = iter->next;
+        g_free(iter->value->string);
+        g_free(iter->value);
+        g_free(iter);
+    }
+}
+
+static void test_visitor_test_add(const char *testpath,
+                                  BERTypePC ber_type,
+                                  TestInputOutputVisitor *data,
+                                  void (*test_func)(TestInputOutputVisitor *data, const void *user_data))
+{
+    char path[64];
+    void (*setup)(TestInputOutputVisitor *data, const void *unused);
+
+    switch (ber_type) {
+    case BER_TYPE_PRIMITIVE:
+        snprintf(path, sizeof(path), "/primitive%s", testpath);
+        setup = visitor_output_setup_primitive;
+        break;
+    default:
+        snprintf(path, sizeof(path), "/constructed%s", testpath);
+        setup = visitor_output_setup_constructed;
+        break;
+    }
+
+    g_test_add(path, TestInputOutputVisitor, data, setup,
+               test_func, visitor_output_teardown);
+}
+
+int main(int argc, char **argv)
+{
+    TestInputOutputVisitor out_visitor_data;
+    BERTypePC types[] = {BER_TYPE_CONSTRUCTED, BER_TYPE_PRIMITIVE};
+    int i;
+
+    g_test_init(&argc, &argv, NULL);
+
+    for (i = 0; i < ARRAY_SIZE(types); i++) {
+        test_visitor_test_add("/visitor/output/int", types[i],
+                              &out_visitor_data, test_visitor_out_int);
+        test_visitor_test_add("/visitor/output/bool", types[i],
+                              &out_visitor_data, test_visitor_out_bool);
+        test_visitor_test_add("/visitor/output/string", types[i],
+                              &out_visitor_data, test_visitor_out_string);
+        test_visitor_test_add("/visitor/output/no-string", types[i],
+                              &out_visitor_data, test_visitor_out_no_string);
+        test_visitor_test_add("/visitor/output/struct", types[i],
+                              &out_visitor_data, test_visitor_out_struct);
+        test_visitor_test_add("/visitor/output/array", types[i],
+                              &out_visitor_data, test_visitor_out_array);
+        test_visitor_test_add("/visitor/output/nested-struct", types[i],
+                              &out_visitor_data,
+                              test_visitor_out_nested_struct);
+        test_visitor_test_add("/visitor/output/list", types[i],
+                              &out_visitor_data, test_visitor_out_list);
+        test_visitor_test_add("/visitor/output/simplestruct_list", types[i],
+                              &out_visitor_data,
+                              test_visitor_out_simplestruct_list);
+    }
+
+    g_test_run();
+
+    return 0;
+}
Index: b/tests/Makefile
===================================================================
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -23,6 +23,10 @@ check-unit-y += tests/test-string-input-
 gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c
 check-unit-y += tests/test-string-output-visitor$(EXESUF)
 gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c
+check-unit-y += tests/test-ber-visitor$(EXESUF)
+gcov-files-test-vistor-y = ber/
+
+
 check-unit-y += tests/test-coroutine$(EXESUF)
 ifeq ($(CONFIG_WIN32),y)
 gcov-files-test-coroutine-y = coroutine-win32.c
@@ -134,6 +138,14 @@ tests/fdc-test$(EXESUF): tests/fdc-test.
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o
 
+ber-dir = ber
+
+tests/test-ber-visitor.o : QEMU_CFLAGS += -I $(ber-dir)
+
+tests/test-ber-visitor.o: $(addprefix $(ber-dir)/, ber-common.c ber.h ber-input-visitor.c ber-input-visitor.h ber-output-visitor.c ber-output-visitor.h) $(ber-obj-y)
+#tests/test-ber-visitor$(EXESUF): tests/test-ber-visitor.o $(tools-obj-y) $(ber-dir)/ber-output-visitor.o $(ber-dir)/ber-input-visitor.o $(ber-dir)/ber-common.o $(block-obj-y) qemu-file.o libqemustub.a $(qobject-obj-y) $(qapi-obj-y)
+tests/test-ber-visitor$(EXESUF): tests/test-ber-visitor.o $(tools-obj-y) $(ber-dir)/ber-output-visitor.o $(ber-dir)/ber-input-visitor.o $(ber-dir)/ber-common.o $(block-obj-y) qemu-file.o libqemuutil.a libqemustub.a
+
 # QTest rules
 
 TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
