Add back (adapted) `test_bt_values` and `test_graph_topo`
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 3 Jul 2019 17:00:01 +0000 (13:00 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 3 Jul 2019 18:32:42 +0000 (14:32 -0400)
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: If030ce3688e94162060ed5d220449bf3f7895c6a
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1603
Tested-by: jenkins <jenkins@lttng.org>
tests/Makefile.am
tests/lib/Makefile.am
tests/lib/test_bt_values.c [new file with mode: 0644]
tests/lib/test_graph_topo.c [new file with mode: 0644]

index 2af0a0c741df7ee09472e6b6eec06cd98349d042..5ffd0e0c959f45214df386ceda95c4fa6cc3226b 100644 (file)
@@ -56,6 +56,8 @@ TESTS_CLI = \
 
 TESTS_LIB = \
        lib/test_bitfield \
+       lib/test_bt_values \
+       lib/test_graph_topo \
        lib/test_trace_ir_ref
 
 TESTS_CTF_WRITER = \
index f19a087bf055b89ca0798e1c87337bf3b7b0764a..efbb6c860deb0a76320af830b0a05a23125aa805 100644 (file)
@@ -8,14 +8,23 @@ COMMON_TEST_LDADD = \
 
 test_bitfield_LDADD = $(COMMON_TEST_LDADD)
 
+test_bt_values_LDADD = $(COMMON_TEST_LDADD) \
+       $(top_builddir)/src/lib/libbabeltrace2.la
+
 test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD) \
        $(top_builddir)/src/lib/libbabeltrace2.la \
        $(top_builddir)/src/ctf-writer/libbabeltrace2-ctf-writer.la
 
-noinst_PROGRAMS = test_bitfield test_trace_ir_ref
+test_graph_topo_LDADD = $(COMMON_TEST_LDADD) \
+       $(top_builddir)/src/lib/libbabeltrace2.la
+
+noinst_PROGRAMS = test_bitfield test_bt_values \
+       test_trace_ir_ref test_graph_topo
 
 test_bitfield_SOURCES = test_bitfield.c
+test_bt_values_SOURCES = test_bt_values.c
 test_trace_ir_ref_SOURCES = test_trace_ir_ref.c
+test_graph_topo_SOURCES = test_graph_topo.c
 
 if !ENABLE_BUILT_IN_PLUGINS
 noinst_PROGRAMS += plugin
diff --git a/tests/lib/test_bt_values.c b/tests/lib/test_bt_values.c
new file mode 100644 (file)
index 0000000..ed7e404
--- /dev/null
@@ -0,0 +1,1117 @@
+/*
+ * test_bt_values.c
+ *
+ * Babeltrace value objects tests
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.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; under version 2 of the License.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/assert.h"
+#include <string.h>
+#include "tap/tap.h"
+
+#define NR_TESTS 166
+
+static
+void test_null(void)
+{
+       ok(bt_value_null, "bt_value_null is not NULL");
+       ok(bt_value_is_null(bt_value_null),
+               "bt_value_null is a null value object");
+       bt_value_get_ref(bt_value_null);
+       pass("getting bt_value_null does not cause a crash");
+       bt_value_put_ref(bt_value_null);
+       pass("putting bt_value_null does not cause a crash");
+}
+
+static
+void test_bool(void)
+{
+       bt_bool value;
+       bt_value *obj;
+
+       obj = bt_value_bool_create();
+       ok(obj && bt_value_is_bool(obj),
+               "bt_value_bool_create() returns a boolean value object");
+
+       value = BT_TRUE;
+       value = bt_value_bool_get(obj);
+       ok(!value, "default boolean value object value is BT_FALSE");
+
+       bt_value_bool_set(obj, BT_FALSE);
+       bt_value_bool_set(obj, BT_TRUE);
+       value = bt_value_bool_get(obj);
+       ok(value, "bt_value_bool_set() works");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       pass("putting an existing boolean value object does not cause a crash")
+
+       value = BT_FALSE;
+       obj = bt_value_bool_create_init(BT_TRUE);
+       ok(obj && bt_value_is_bool(obj),
+               "bt_value_bool_create_init() returns a boolean value object");
+       value = bt_value_bool_get(obj);
+       ok(value,
+               "bt_value_bool_create_init() sets the appropriate initial value");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+}
+
+static
+void test_unsigned_integer(void)
+{
+       uint64_t value;
+       bt_value *obj;
+
+       obj = bt_value_unsigned_integer_create();
+       ok(obj && bt_value_is_unsigned_integer(obj),
+               "bt_value_unsigned_integer_create() returns an unsigned integer value object");
+
+       value = 1961;
+       value = bt_value_unsigned_integer_get(obj);
+       ok(value == 0, "default unsigned integer value object value is 0");
+
+       bt_value_unsigned_integer_set(obj, 98765);
+       value = bt_value_unsigned_integer_get(obj);
+       ok(value == 98765, "bt_value_unsigned_integer_bool_set() works");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       pass("putting an existing unsigned integer value object does not cause a crash")
+
+       obj = bt_value_unsigned_integer_create_init(321456987);
+       ok(obj && bt_value_is_unsigned_integer(obj),
+               "bt_value_unsigned_integer_create_init() returns an unsigned integer value object");
+       value = bt_value_unsigned_integer_get(obj);
+       ok(value == 321456987,
+               "bt_value_unsigned_integer_create_init() sets the appropriate initial value");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+}
+
+static
+void test_signed_integer(void)
+{
+       int64_t value;
+       bt_value *obj;
+
+       obj = bt_value_signed_integer_create();
+       ok(obj && bt_value_is_signed_integer(obj),
+               "bt_value_signed_integer_create() returns a signed integer value object");
+
+       value = 1961;
+       value = bt_value_signed_integer_get(obj);
+       ok(value == 0, "default signed integer value object value is 0");
+
+       bt_value_signed_integer_set(obj, 98765);
+       value = bt_value_signed_integer_get(obj);
+       ok(value == 98765, "bt_value_signed_integer_bool_set() works");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       pass("putting an existing signed integer value object does not cause a crash")
+
+       obj = bt_value_signed_integer_create_init(-321456987);
+       ok(obj && bt_value_is_signed_integer(obj),
+               "bt_value_signed_integer_create_init() returns a signed integer value object");
+       value = bt_value_signed_integer_get(obj);
+       ok(value == -321456987,
+               "bt_value_signed_integer_create_init() sets the appropriate initial value");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+}
+
+static
+void test_real(void)
+{
+       double value;
+       bt_value *obj;
+
+       obj = bt_value_real_create();
+       ok(obj && bt_value_is_real(obj),
+               "bt_value_real_create() returns a real number value object");
+
+       value = 17.34;
+       value = bt_value_real_get(obj);
+       ok(value == 0.,
+               "default real number value object value is 0");
+
+       bt_value_real_set(obj, -3.1416);
+       value = bt_value_real_get(obj);
+       ok(value == -3.1416, "bt_value_real_set() works");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       pass("putting an existing real number value object does not cause a crash")
+
+       obj = bt_value_real_create_init(33.1649758);
+       ok(obj && bt_value_is_real(obj),
+               "bt_value_real_create_init() returns a real number value object");
+       value = bt_value_real_get(obj);
+       ok(value == 33.1649758,
+               "bt_value_real_create_init() sets the appropriate initial value");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+}
+
+static
+void test_string(void)
+{
+       const char *value;
+       bt_value *obj;
+
+       obj = bt_value_string_create();
+       ok(obj && bt_value_is_string(obj),
+               "bt_value_string_create() returns a string value object");
+
+       value = bt_value_string_get(obj);
+       ok(value && !strcmp(value, ""),
+               "default string value object value is \"\"");
+
+       bt_value_string_set(obj, "hello worldz");
+       value = bt_value_string_get(obj);
+       ok(value && !strcmp(value, "hello worldz"),
+               "bt_value_string_get() works");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       pass("putting an existing string value object does not cause a crash")
+
+       obj = bt_value_string_create_init("initial value");
+       ok(obj && bt_value_is_string(obj),
+               "bt_value_string_create_init() returns a string value object");
+       value = bt_value_string_get(obj);
+       ok(value && !strcmp(value, "initial value"),
+               "bt_value_string_create_init() sets the appropriate initial value");
+
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+}
+
+static
+void test_array(void)
+{
+       int ret;
+       bt_bool bool_value;
+       int64_t int_value;
+       double real_value;
+       bt_value *obj;
+       const char *string_value;
+       bt_value *array_obj;
+
+       array_obj = bt_value_array_create();
+       ok(array_obj && bt_value_is_array(array_obj),
+               "bt_value_array_create() returns an array value object");
+       ok(bt_value_array_is_empty(array_obj),
+               "initial array value object size is 0");
+
+       obj = bt_value_unsigned_integer_create_init(345);
+       ret = bt_value_array_append_element(array_obj, obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_signed_integer_create_init(-507);
+       ret |= bt_value_array_append_element(array_obj, obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_real_create_init(-17.45);
+       ret |= bt_value_array_append_element(array_obj, obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_bool_create_init(BT_TRUE);
+       ret |= bt_value_array_append_element(array_obj, obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       ret |= bt_value_array_append_element(array_obj,
+               bt_value_null);
+       ok(!ret, "bt_value_array_append_element() succeeds");
+       ok(bt_value_array_get_size(array_obj) == 5,
+               "appending an element to an array value object increment its size");
+
+       obj = bt_value_array_borrow_element_by_index(array_obj, 0);
+       ok(obj && bt_value_is_unsigned_integer(obj),
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate type (unsigned integer)");
+       int_value = bt_value_unsigned_integer_get(obj);
+       ok(int_value == 345,
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate value (unsigned integer)");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 1);
+       ok(obj && bt_value_is_signed_integer(obj),
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate type (signed integer)");
+       int_value = bt_value_signed_integer_get(obj);
+       ok(int_value == -507,
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate value (signed integer)");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 2);
+       ok(obj && bt_value_is_real(obj),
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate type (real number)");
+       real_value = bt_value_real_get(obj);
+       ok(real_value == -17.45,
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate value (real number)");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 3);
+       ok(obj && bt_value_is_bool(obj),
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate type (boolean)");
+       bool_value = bt_value_bool_get(obj);
+       ok(bool_value,
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate value (boolean)");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 4);
+       ok(obj == bt_value_null,
+               "bt_value_array_borrow_element_by_index() returns an value object with the appropriate type (null)");
+
+       obj = bt_value_signed_integer_create_init(1001);
+       BT_ASSERT(obj);
+       ok(!bt_value_array_set_element_by_index(array_obj, 2, obj),
+               "bt_value_array_set_element_by_index() succeeds");
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_array_borrow_element_by_index(array_obj, 2);
+       ok(obj && bt_value_is_signed_integer(obj),
+               "bt_value_array_set_element_by_index() inserts an value object with the appropriate type");
+       int_value = bt_value_signed_integer_get(obj);
+       BT_ASSERT(!ret);
+       ok(int_value == 1001,
+               "bt_value_array_set_element_by_index() inserts an value object with the appropriate value");
+
+       ret = bt_value_array_append_bool_element(array_obj,
+               BT_FALSE);
+       ok(!ret, "bt_value_array_append_bool_element() succeeds");
+       ret = bt_value_array_append_unsigned_integer_element(array_obj,
+               98765);
+       ok(!ret, "bt_value_array_append_unsigned_integer_element() succeeds");
+       ret = bt_value_array_append_signed_integer_element(array_obj,
+               -10101);
+       ok(!ret, "bt_value_array_append_signed_integer_element() succeeds");
+       ret = bt_value_array_append_real_element(array_obj,
+               2.49578);
+       ok(!ret, "bt_value_array_append_real_element() succeeds");
+       ret = bt_value_array_append_string_element(array_obj,
+               "bt_value");
+       ok(!ret, "bt_value_array_append_string_element() succeeds");
+       ret = bt_value_array_append_empty_array_element(array_obj);
+       ok(!ret, "bt_value_array_append_empty_array_element() succeeds");
+       ret = bt_value_array_append_empty_map_element(array_obj);
+       ok(!ret, "bt_value_array_append_empty_map_element() succeeds");
+
+       ok(bt_value_array_get_size(array_obj) == 12,
+               "the bt_value_array_append_element_*() functions increment the array value object's size");
+       ok(!bt_value_array_is_empty(array_obj),
+               "map value object is not empty");
+
+       obj = bt_value_array_borrow_element_by_index(array_obj, 5);
+       ok(obj && bt_value_is_bool(obj),
+               "bt_value_array_append_bool_element() appends a boolean value object");
+       bool_value = bt_value_bool_get(obj);
+       ok(!bool_value,
+               "bt_value_array_append_bool_element() appends the appropriate value");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 6);
+       ok(obj && bt_value_is_unsigned_integer(obj),
+               "bt_value_array_append_unsigned_integer_element() appends an unsigned integer value object");
+       int_value = bt_value_unsigned_integer_get(obj);
+       ok(int_value == 98765,
+               "bt_value_array_append_unsigned_integer_element() appends the appropriate value");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 7);
+       ok(obj && bt_value_is_signed_integer(obj),
+               "bt_value_array_append_signed_integer_element() appends a signed integer value object");
+       int_value = bt_value_signed_integer_get(obj);
+       ok(int_value == -10101,
+               "bt_value_array_append_signed_integer_element() appends the appropriate value");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 8);
+       ok(obj && bt_value_is_real(obj),
+               "bt_value_array_append_real_element() appends a real number value object");
+       real_value = bt_value_real_get(obj);
+       ok(real_value == 2.49578,
+               "bt_value_array_append_real_element() appends the appropriate value");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 9);
+       ok(obj && bt_value_is_string(obj),
+               "bt_value_array_append_string_element() appends a string value object");
+       string_value = bt_value_string_get(obj);
+       ok(!ret && string_value && !strcmp(string_value, "bt_value"),
+               "bt_value_array_append_string_element() appends the appropriate value");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 10);
+       ok(obj && bt_value_is_array(obj),
+               "bt_value_array_append_empty_array_element() appends an array value object");
+       ok(bt_value_array_is_empty(obj),
+               "bt_value_array_append_empty_array_element() an empty array value object");
+       obj = bt_value_array_borrow_element_by_index(array_obj, 11);
+       ok(obj && bt_value_is_map(obj),
+               "bt_value_array_append_empty_map_element() appends a map value object");
+       ok(bt_value_map_is_empty(obj),
+               "bt_value_array_append_empty_map_element() an empty map value object");
+
+       BT_VALUE_PUT_REF_AND_RESET(array_obj);
+       pass("putting an existing array value object does not cause a crash")
+}
+
+static
+bt_bool test_map_foreach_cb_count(const char *key, bt_value *object,
+       void *data)
+{
+       int *count = data;
+
+       if (*count == 3) {
+               return BT_FALSE;
+       }
+
+       (*count)++;
+
+       return BT_TRUE;
+}
+
+struct map_foreach_checklist {
+       bt_bool bool1;
+       bt_bool uint;
+       bt_bool int1;
+       bt_bool real1;
+       bt_bool null1;
+       bt_bool bool2;
+       bt_bool int2;
+       bt_bool real2;
+       bt_bool string2;
+       bt_bool array2;
+       bt_bool map2;
+};
+
+static
+bt_bool test_map_foreach_cb_check(const char *key, bt_value *object,
+       void *data)
+{
+       struct map_foreach_checklist *checklist = data;
+
+       if (!strcmp(key, "bt_bool")) {
+               if (checklist->bool1) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"bt_bool\"");
+               } else {
+                       bt_bool val = BT_FALSE;
+
+                       val = bt_value_bool_get(object);
+
+                       if (val) {
+                               pass("test_map_foreach_cb_check(): \"bt_bool\" value object has the right value");
+                               checklist->bool1 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"bt_bool\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "uint")) {
+               if (checklist->uint) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"uint\"");
+               } else {
+                       uint64_t val = 0;
+
+                       val = bt_value_unsigned_integer_get(object);
+
+                       if (val == 19457) {
+                               pass("test_map_foreach_cb_check(): \"uint\" value object has the right value");
+                               checklist->uint = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"uint\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "int")) {
+               if (checklist->int1) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"int\"");
+               } else {
+                       int64_t val = 0;
+
+                       val = bt_value_signed_integer_get(object);
+
+                       if (val == -12345) {
+                               pass("test_map_foreach_cb_check(): \"int\" value object has the right value");
+                               checklist->int1 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"int\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "real")) {
+               if (checklist->real1) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"real\"");
+               } else {
+                       double val = 0;
+
+                       val = bt_value_real_get(object);
+
+                       if (val == 5.444) {
+                               pass("test_map_foreach_cb_check(): \"real\" value object has the right value");
+                               checklist->real1 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"real\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "null")) {
+               if (checklist->null1) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"bt_bool\"");
+               } else {
+                       ok(bt_value_is_null(object), "test_map_foreach_cb_check(): success getting \"null\" value object");
+                       checklist->null1 = BT_TRUE;
+               }
+       } else if (!strcmp(key, "bool2")) {
+               if (checklist->bool2) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"bool2\"");
+               } else {
+                       bt_bool val = BT_FALSE;
+
+                       val = bt_value_bool_get(object);
+
+                       if (val) {
+                               pass("test_map_foreach_cb_check(): \"bool2\" value object has the right value");
+                               checklist->bool2 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"bool2\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "int2")) {
+               if (checklist->int2) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"int2\"");
+               } else {
+                       int64_t val = 0;
+
+                       val = bt_value_signed_integer_get(object);
+
+                       if (val == 98765) {
+                               pass("test_map_foreach_cb_check(): \"int2\" value object has the right value");
+                               checklist->int2 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"int2\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "real2")) {
+               if (checklist->real2) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"real2\"");
+               } else {
+                       double val = 0;
+
+                       val = bt_value_real_get(object);
+
+                       if (val == -49.0001) {
+                               pass("test_map_foreach_cb_check(): \"real2\" value object has the right value");
+                               checklist->real2 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"real2\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "string2")) {
+               if (checklist->string2) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"string2\"");
+               } else {
+                       const char *val;
+
+                       val = bt_value_string_get(object);
+
+                       if (val && !strcmp(val, "bt_value")) {
+                               pass("test_map_foreach_cb_check(): \"string2\" value object has the right value");
+                               checklist->string2 = BT_TRUE;
+                       } else {
+                               fail("test_map_foreach_cb_check(): \"string2\" value object has the wrong value");
+                       }
+               }
+       } else if (!strcmp(key, "array2")) {
+               if (checklist->array2) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"array2\"");
+               } else {
+                       ok(bt_value_is_array(object), "test_map_foreach_cb_check(): success getting \"array2\" value object");
+                       ok(bt_value_array_is_empty(object),
+                               "test_map_foreach_cb_check(): \"array2\" value object is empty");
+                       checklist->array2 = BT_TRUE;
+               }
+       } else if (!strcmp(key, "map2")) {
+               if (checklist->map2) {
+                       fail("test_map_foreach_cb_check(): duplicate key \"map2\"");
+               } else {
+                       ok(bt_value_is_map(object), "test_map_foreach_cb_check(): success getting \"map2\" value object");
+                       ok(bt_value_map_is_empty(object),
+                               "test_map_foreach_cb_check(): \"map2\" value object is empty");
+                       checklist->map2 = BT_TRUE;
+               }
+       } else {
+               fail("test_map_foreach_cb_check(): unknown map key \"%s\"",
+                       key);
+       }
+
+       return BT_TRUE;
+}
+
+static
+void test_map(void)
+{
+       int ret;
+       int count = 0;
+       bt_bool bool_value;
+       int64_t int_value;
+       double real_value;
+       bt_value *obj;
+       bt_value *map_obj;
+       struct map_foreach_checklist checklist;
+
+       map_obj = bt_value_map_create();
+       ok(map_obj && bt_value_is_map(map_obj),
+               "bt_value_map_create() returns a map value object");
+       ok(bt_value_map_get_size(map_obj) == 0,
+               "initial map value object size is 0");
+
+       obj = bt_value_unsigned_integer_create_init(19457);
+       ret = bt_value_map_insert_entry(map_obj, "uint", obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_signed_integer_create_init(-12345);
+       ret |= bt_value_map_insert_entry(map_obj, "int", obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_real_create_init(5.444);
+       ret |= bt_value_map_insert_entry(map_obj, "real", obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       obj = bt_value_bool_create();
+       ret |= bt_value_map_insert_entry(map_obj, "bt_bool", obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       ret |= bt_value_map_insert_entry(map_obj, "null",
+               bt_value_null);
+       ok(!ret, "bt_value_map_insert_entry() succeeds");
+       ok(bt_value_map_get_size(map_obj) == 5,
+               "inserting an element into a map value object increment its size");
+
+       obj = bt_value_bool_create_init(BT_TRUE);
+       ret = bt_value_map_insert_entry(map_obj, "bt_bool", obj);
+       BT_VALUE_PUT_REF_AND_RESET(obj);
+       ok(!ret, "bt_value_map_insert_entry() accepts an existing key");
+
+       obj = bt_value_map_borrow_entry_value(map_obj, "life");
+       ok(!obj, "bt_value_map_borrow_entry_value() returns NULL with an non existing key");
+       obj = bt_value_map_borrow_entry_value(map_obj, "real");
+       ok(obj && bt_value_is_real(obj),
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate type (real)");
+       real_value = bt_value_real_get(obj);
+       ok(real_value == 5.444,
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate value (real)");
+       obj = bt_value_map_borrow_entry_value(map_obj, "uint");
+       ok(obj && bt_value_is_unsigned_integer(obj),
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate type (unsigned integer)");
+       int_value = bt_value_unsigned_integer_get(obj);
+       ok(int_value == 19457,
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate value (unsigned integer)");
+       obj = bt_value_map_borrow_entry_value(map_obj, "int");
+       ok(obj && bt_value_is_signed_integer(obj),
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate type (signed integer)");
+       int_value = bt_value_signed_integer_get(obj);
+       ok(int_value == -12345,
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate value (signed integer)");
+       obj = bt_value_map_borrow_entry_value(map_obj, "null");
+       ok(obj && bt_value_is_null(obj),
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate type (null)");
+       obj = bt_value_map_borrow_entry_value(map_obj, "bt_bool");
+       ok(obj && bt_value_is_bool(obj),
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate type (boolean)");
+       bool_value = bt_value_bool_get(obj);
+       ok(bool_value,
+               "bt_value_map_borrow_entry_value() returns an value object with the appropriate value (boolean)");
+
+       ret = bt_value_map_insert_bool_entry(map_obj, "bool2",
+               BT_TRUE);
+       ok(!ret, "bt_value_map_insert_bool_entry() succeeds");
+       ret = bt_value_map_insert_signed_integer_entry(map_obj, "int2",
+               98765);
+       ok(!ret, "bt_value_map_insert_signed_integer_entry() succeeds");
+       ret = bt_value_map_insert_real_entry(map_obj, "real2",
+               -49.0001);
+       ok(!ret, "bt_value_map_insert_real_entry() succeeds");
+       ret = bt_value_map_insert_string_entry(map_obj, "string2",
+               "bt_value");
+       ok(!ret, "bt_value_map_insert_string_entry() succeeds");
+       ret = bt_value_map_insert_empty_array_entry(map_obj,
+               "array2");
+       ok(!ret, "bt_value_map_insert_empty_array_entry() succeeds");
+       ret = bt_value_map_insert_empty_map_entry(map_obj, "map2");
+       ok(!ret, "bt_value_map_insert_empty_map_entry() succeeds");
+
+       ok(bt_value_map_get_size(map_obj) == 11,
+               "the bt_value_map_insert*() functions increment the map value object's size");
+
+       ok(!bt_value_map_has_entry(map_obj, "hello"),
+               "map value object does not have key \"hello\"");
+       ok(bt_value_map_has_entry(map_obj, "bt_bool"),
+               "map value object has key \"bt_bool\"");
+       ok(bt_value_map_has_entry(map_obj, "uint"),
+               "map value object has key \"uint\"");
+       ok(bt_value_map_has_entry(map_obj, "int"),
+               "map value object has key \"int\"");
+       ok(bt_value_map_has_entry(map_obj, "real"),
+               "map value object has key \"real\"");
+       ok(bt_value_map_has_entry(map_obj, "null"),
+               "map value object has key \"null\"");
+       ok(bt_value_map_has_entry(map_obj, "bool2"),
+               "map value object has key \"bool2\"");
+       ok(bt_value_map_has_entry(map_obj, "int2"),
+               "map value object has key \"int2\"");
+       ok(bt_value_map_has_entry(map_obj, "real2"),
+               "map value object has key \"real2\"");
+       ok(bt_value_map_has_entry(map_obj, "string2"),
+               "map value object has key \"string2\"");
+       ok(bt_value_map_has_entry(map_obj, "array2"),
+               "map value object has key \"array2\"");
+       ok(bt_value_map_has_entry(map_obj, "map2"),
+               "map value object has key \"map2\"");
+
+       ret = bt_value_map_foreach_entry(map_obj, test_map_foreach_cb_count,
+               &count);
+       ok(ret == BT_VALUE_MAP_FOREACH_ENTRY_STATUS_CANCELED && count == 3,
+               "bt_value_map_foreach_entry() breaks the loop when the user function returns BT_FALSE");
+
+       memset(&checklist, 0, sizeof(checklist));
+       ret = bt_value_map_foreach_entry(map_obj, test_map_foreach_cb_check,
+               &checklist);
+       ok(ret == BT_VALUE_MAP_FOREACH_ENTRY_STATUS_OK,
+               "bt_value_map_foreach_entry() succeeds with test_map_foreach_cb_check()");
+       ok(checklist.bool1 && checklist.uint && checklist.int1 &&
+               checklist.real1 && checklist.null1 && checklist.bool2 &&
+               checklist.int2 && checklist.real2 && checklist.string2 &&
+               checklist.array2 && checklist.map2,
+               "bt_value_map_foreach_entry() iterates over all the map value object's elements");
+
+       BT_VALUE_PUT_REF_AND_RESET(map_obj);
+       pass("putting an existing map value object does not cause a crash")
+}
+
+static
+void test_types(void)
+{
+       test_null();
+       test_bool();
+       test_unsigned_integer();
+       test_signed_integer();
+       test_real();
+       test_string();
+       test_array();
+       test_map();
+}
+
+static
+void test_compare_null(void)
+{
+       ok(bt_value_compare(bt_value_null, bt_value_null),
+               "null value objects are equivalent");
+}
+
+static
+void test_compare_bool(void)
+{
+       bt_value *bool1 =
+               bt_value_bool_create_init(BT_FALSE);
+       bt_value *bool2 =
+               bt_value_bool_create_init(BT_TRUE);
+       bt_value *bool3 =
+               bt_value_bool_create_init(BT_FALSE);
+
+       BT_ASSERT(bool1 && bool2 && bool3);
+       ok(!bt_value_compare(bt_value_null,
+               bool1),
+               "cannot compare null value object and bt_bool value object");
+       ok(!bt_value_compare(bool1,
+                            bool2),
+               "boolean value objects are not equivalent (BT_FALSE and BT_TRUE)");
+       ok(bt_value_compare(bool1,
+                           bool3),
+               "boolean value objects are equivalent (BT_FALSE and BT_FALSE)");
+
+       BT_VALUE_PUT_REF_AND_RESET(bool1);
+       BT_VALUE_PUT_REF_AND_RESET(bool2);
+       BT_VALUE_PUT_REF_AND_RESET(bool3);
+}
+
+static
+void test_compare_unsigned_integer(void)
+{
+       bt_value *int1 =
+               bt_value_unsigned_integer_create_init(10);
+       bt_value *int2 =
+               bt_value_unsigned_integer_create_init(23);
+       bt_value *int3 =
+               bt_value_unsigned_integer_create_init(10);
+
+       BT_ASSERT(int1 && int2 && int3);
+       ok(!bt_value_compare(bt_value_null,
+               int1),
+               "cannot compare null value object and unsigned integer value object");
+       ok(!bt_value_compare(int1, int2),
+               "unsigned integer value objects are not equivalent (10 and 23)");
+       ok(bt_value_compare(int1, int3),
+               "unsigned integer value objects are equivalent (10 and 10)");
+
+       BT_VALUE_PUT_REF_AND_RESET(int1);
+       BT_VALUE_PUT_REF_AND_RESET(int2);
+       BT_VALUE_PUT_REF_AND_RESET(int3);
+}
+
+void test_compare_signed_integer(void)
+{
+       bt_value *int1 =
+               bt_value_signed_integer_create_init(10);
+       bt_value *int2 =
+               bt_value_signed_integer_create_init(-23);
+       bt_value *int3 =
+               bt_value_signed_integer_create_init(10);
+
+       BT_ASSERT(int1 && int2 && int3);
+       ok(!bt_value_compare(bt_value_null,
+               int1),
+               "cannot compare null value object and signed integer value object");
+       ok(!bt_value_compare(int1, int2),
+               "signed integer value objects are not equivalent (10 and -23)");
+       ok(bt_value_compare(int1, int3),
+               "signed integer value objects are equivalent (10 and 10)");
+
+       BT_VALUE_PUT_REF_AND_RESET(int1);
+       BT_VALUE_PUT_REF_AND_RESET(int2);
+       BT_VALUE_PUT_REF_AND_RESET(int3);
+}
+
+static
+void test_compare_real(void)
+{
+       bt_value *real1 =
+               bt_value_real_create_init(17.38);
+       bt_value *real2 =
+               bt_value_real_create_init(-14.23);
+       bt_value *real3 =
+               bt_value_real_create_init(17.38);
+
+       BT_ASSERT(real1 && real2 && real3);
+
+       ok(!bt_value_compare(bt_value_null,
+               real1),
+               "cannot compare null value object and real number value object");
+       ok(!bt_value_compare(real1,
+                            real2),
+               "real number value objects are not equivalent (17.38 and -14.23)");
+       ok(bt_value_compare(real1,
+                           real3),
+               "real number value objects are equivalent (17.38 and 17.38)");
+
+       BT_VALUE_PUT_REF_AND_RESET(real1);
+       BT_VALUE_PUT_REF_AND_RESET(real2);
+       BT_VALUE_PUT_REF_AND_RESET(real3);
+}
+
+static
+void test_compare_string(void)
+{
+       bt_value *string1 =
+               bt_value_string_create_init("hello");
+       bt_value *string2 =
+               bt_value_string_create_init("bt_value");
+       bt_value *string3 =
+               bt_value_string_create_init("hello");
+
+       BT_ASSERT(string1 && string2 && string3);
+
+       ok(!bt_value_compare(bt_value_null,
+               string1),
+               "cannot compare null value object and string value object");
+       ok(!bt_value_compare(string1,
+                            string2),
+               "string value objects are not equivalent (\"hello\" and \"bt_value\")");
+       ok(bt_value_compare(string1,
+                           string3),
+               "string value objects are equivalent (\"hello\" and \"hello\")");
+
+       BT_VALUE_PUT_REF_AND_RESET(string1);
+       BT_VALUE_PUT_REF_AND_RESET(string2);
+       BT_VALUE_PUT_REF_AND_RESET(string3);
+}
+
+static
+void test_compare_array(void)
+{
+       bt_value *array1 = bt_value_array_create();
+       bt_value *array2 = bt_value_array_create();
+       bt_value *array3 = bt_value_array_create();
+       bt_value_array_append_element_status append_status;
+
+       BT_ASSERT(array1 && array2 && array3);
+
+       ok(bt_value_compare(array1, array2),
+               "empty array value objects are equivalent");
+
+       append_status = bt_value_array_append_signed_integer_element(array1, 23);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_real_element(array1, 14.2);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_bool_element(array1, BT_FALSE);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_real_element(array2, 14.2);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_signed_integer_element(array2, 23);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_bool_element(array2, BT_FALSE);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_signed_integer_element(array3, 23);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_real_element(array3, 14.2);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_bool_element(array3, BT_FALSE);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       BT_ASSERT(bt_value_array_get_size(array1) == 3);
+       BT_ASSERT(bt_value_array_get_size(array2) == 3);
+       BT_ASSERT(bt_value_array_get_size(array3) == 3);
+
+       ok(!bt_value_compare(bt_value_null,
+               array1),
+               "cannot compare null value object and array value object");
+       ok(!bt_value_compare(array1,
+                            array2),
+               "array value objects are not equivalent ([23, 14.2, BT_FALSE] and [14.2, 23, BT_FALSE])");
+       ok(bt_value_compare(array1,
+                           array3),
+               "array value objects are equivalent ([23, 14.2, BT_FALSE] and [23, 14.2, BT_FALSE])");
+
+       BT_VALUE_PUT_REF_AND_RESET(array1);
+       BT_VALUE_PUT_REF_AND_RESET(array2);
+       BT_VALUE_PUT_REF_AND_RESET(array3);
+}
+
+static
+void test_compare_map(void)
+{
+       bt_value *map1 = bt_value_map_create();
+       bt_value *map2 = bt_value_map_create();
+       bt_value *map3 = bt_value_map_create();
+       bt_value_map_insert_entry_status insert_status;
+
+       BT_ASSERT(map1 && map2 && map3);
+
+       ok(bt_value_compare(map1,
+                           map2),
+               "empty map value objects are equivalent");
+
+
+       insert_status = bt_value_map_insert_signed_integer_entry(map1, "one", 23);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_real_entry(map1, "two", 14.2);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_bool_entry(map1, "three",
+               BT_FALSE);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_real_entry(map2, "one", 14.2);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_signed_integer_entry(map2, "two", 23);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_bool_entry(map2, "three",
+               BT_FALSE);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_bool_entry(map3, "three",
+               BT_FALSE);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_signed_integer_entry(map3, "one", 23);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_real_entry(map3, "two", 14.2);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       BT_ASSERT(bt_value_map_get_size(map1) == 3);
+       BT_ASSERT(bt_value_map_get_size(map2) == 3);
+       BT_ASSERT(bt_value_map_get_size(map3) == 3);
+
+       ok(!bt_value_compare(bt_value_null,
+               map1),
+               "cannot compare null value object and map value object");
+       ok(!bt_value_compare(map1,
+                            map2),
+               "map value objects are not equivalent");
+       ok(bt_value_compare(map1,
+                           map3),
+               "map value objects are equivalent");
+
+       BT_VALUE_PUT_REF_AND_RESET(map1);
+       BT_VALUE_PUT_REF_AND_RESET(map2);
+       BT_VALUE_PUT_REF_AND_RESET(map3);
+}
+
+static
+void test_compare(void)
+{
+       test_compare_null();
+       test_compare_bool();
+       test_compare_unsigned_integer();
+       test_compare_signed_integer();
+       test_compare_real();
+       test_compare_string();
+       test_compare_array();
+       test_compare_map();
+}
+
+static
+void test_copy(void)
+{
+       /*
+        * Here's the deal here. If we make sure that each value object
+        * of our deep copy has a different address than its source, and
+        * that bt_value_compare() returns BT_TRUE for the top-level
+        * value object, taking into account that we test the
+        * correctness of bt_value_compare() elsewhere, then the deep
+        * copy is a success.
+        */
+       bt_value *null_copy_obj;
+       bt_value *bool_obj, *bool_copy_obj;
+       bt_value *unsigned_integer_obj, *unsigned_integer_copy_obj;
+       bt_value *signed_integer_obj, *signed_integer_copy_obj;
+       bt_value *real_obj, *real_copy_obj;
+       bt_value *string_obj, *string_copy_obj;
+       bt_value *array_obj, *array_copy_obj;
+       bt_value *map_obj, *map_copy_obj;
+       bt_value_array_append_element_status append_status;
+       bt_value_map_insert_entry_status insert_status;
+       bt_value_copy_status copy_status;
+
+       bool_obj = bt_value_bool_create_init(BT_TRUE);
+       unsigned_integer_obj = bt_value_unsigned_integer_create_init(23);
+       signed_integer_obj = bt_value_signed_integer_create_init(-47);
+       real_obj = bt_value_real_create_init(-3.1416);
+       string_obj = bt_value_string_create_init("test");
+       array_obj = bt_value_array_create();
+       map_obj = bt_value_map_create();
+
+       BT_ASSERT(bool_obj && unsigned_integer_obj && signed_integer_obj &&
+               real_obj && string_obj && array_obj && map_obj);
+
+       append_status = bt_value_array_append_element(array_obj, bool_obj);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_element(array_obj, unsigned_integer_obj);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_element(array_obj, signed_integer_obj);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_element(array_obj, real_obj);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       append_status = bt_value_array_append_element(array_obj, bt_value_null);
+       BT_ASSERT(append_status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK);
+       insert_status = bt_value_map_insert_entry(map_obj, "array", array_obj);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_entry(map_obj, "string", string_obj);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+
+       copy_status = bt_value_copy(map_obj, &map_copy_obj);
+       ok(copy_status == BT_VALUE_COPY_STATUS_OK && map_copy_obj,
+               "bt_value_copy() succeeds");
+
+       ok(map_obj != map_copy_obj,
+               "bt_value_copy() returns a different pointer (map)");
+       string_copy_obj = bt_value_map_borrow_entry_value(map_copy_obj,
+               "string");
+       ok(string_copy_obj != string_obj,
+               "bt_value_copy() returns a different pointer (string)");
+       array_copy_obj = bt_value_map_borrow_entry_value(map_copy_obj,
+               "array");
+       ok(array_copy_obj != array_obj,
+               "bt_value_copy() returns a different pointer (array)");
+       bool_copy_obj = bt_value_array_borrow_element_by_index(
+               array_copy_obj, 0);
+       ok(bool_copy_obj != bool_obj,
+               "bt_value_copy() returns a different pointer (bool)");
+       unsigned_integer_copy_obj = bt_value_array_borrow_element_by_index(
+               array_copy_obj, 1);
+       ok(unsigned_integer_copy_obj != unsigned_integer_obj,
+               "bt_value_copy() returns a different pointer (unsigned integer)");
+       signed_integer_copy_obj = bt_value_array_borrow_element_by_index(
+               array_copy_obj, 2);
+       ok(signed_integer_copy_obj != signed_integer_obj,
+               "bt_value_copy() returns a different pointer (signed integer)");
+       real_copy_obj = bt_value_array_borrow_element_by_index(
+               array_copy_obj, 3);
+       ok(real_copy_obj != real_obj,
+               "bt_value_copy() returns a different pointer (real)");
+       null_copy_obj = bt_value_array_borrow_element_by_index(
+               array_copy_obj, 4);
+       ok(null_copy_obj == bt_value_null,
+               "bt_value_copy() returns the same pointer (null)");
+
+       ok(bt_value_compare(map_obj, map_copy_obj),
+               "source and destination value objects have the same content");
+
+       BT_VALUE_PUT_REF_AND_RESET(map_copy_obj);
+       BT_VALUE_PUT_REF_AND_RESET(bool_obj);
+       BT_VALUE_PUT_REF_AND_RESET(unsigned_integer_obj);
+       BT_VALUE_PUT_REF_AND_RESET(signed_integer_obj);
+       BT_VALUE_PUT_REF_AND_RESET(real_obj);
+       BT_VALUE_PUT_REF_AND_RESET(string_obj);
+       BT_VALUE_PUT_REF_AND_RESET(array_obj);
+       BT_VALUE_PUT_REF_AND_RESET(map_obj);
+}
+
+static
+bt_bool compare_map_elements(const bt_value *map_a, const bt_value *map_b,
+               const char *key)
+{
+       const bt_value *elem_a = NULL;
+       const bt_value *elem_b = NULL;
+       bt_bool equal;
+
+       elem_a = bt_value_map_borrow_entry_value_const(map_a, key);
+       elem_b = bt_value_map_borrow_entry_value_const(map_b, key);
+       equal = bt_value_compare(elem_a, elem_b);
+       return equal;
+}
+
+static
+void test_extend(void)
+{
+       bt_value *base_map = bt_value_map_create();
+       bt_value *extension_map = bt_value_map_create();
+       bt_value *extended_map = NULL;
+       bt_value *array = bt_value_array_create();
+       bt_value_map_insert_entry_status insert_status;
+       bt_value_map_extend_status extend_status;
+
+       BT_ASSERT(base_map);
+       BT_ASSERT(extension_map);
+       BT_ASSERT(array);
+       insert_status = bt_value_map_insert_bool_entry(base_map, "file",
+               BT_TRUE);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_bool_entry(base_map, "edit",
+               BT_FALSE);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_signed_integer_entry(base_map,
+               "selection", 17);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_signed_integer_entry(base_map, "find",
+               -34);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_bool_entry(extension_map, "edit",
+               BT_TRUE);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_signed_integer_entry(extension_map,
+               "find", 101);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       insert_status = bt_value_map_insert_real_entry(extension_map,
+               "project", -404);
+       BT_ASSERT(insert_status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK);
+       extend_status = bt_value_map_extend(base_map, extension_map, &extended_map);
+       ok(extend_status == BT_VALUE_MAP_EXTEND_STATUS_OK &&
+               extended_map, "bt_value_map_extend() succeeds");
+       ok(bt_value_map_get_size(extended_map) == 5,
+               "bt_value_map_extend() returns a map object with the correct size");
+       ok(compare_map_elements(base_map,
+                               extended_map, "file"),
+               "bt_value_map_extend() picks the appropriate element (file)");
+       ok(compare_map_elements(extension_map,
+                               extended_map, "edit"),
+               "bt_value_map_extend() picks the appropriate element (edit)");
+       ok(compare_map_elements(base_map,
+                               extended_map, "selection"),
+               "bt_value_map_extend() picks the appropriate element (selection)");
+       ok(compare_map_elements(extension_map,
+                               extended_map, "find"),
+               "bt_value_map_extend() picks the appropriate element (find)");
+       ok(compare_map_elements(extension_map,
+                               extended_map, "project"),
+               "bt_value_map_extend() picks the appropriate element (project)");
+
+       BT_VALUE_PUT_REF_AND_RESET(array);
+       BT_VALUE_PUT_REF_AND_RESET(base_map);
+       BT_VALUE_PUT_REF_AND_RESET(extension_map);
+       BT_VALUE_PUT_REF_AND_RESET(extended_map);
+}
+
+int main(void)
+{
+       plan_tests(NR_TESTS);
+       test_types();
+       test_compare();
+       test_copy();
+       test_extend();
+       return 0;
+}
diff --git a/tests/lib/test_graph_topo.c b/tests/lib/test_graph_topo.c
new file mode 100644 (file)
index 0000000..b4ea1cb
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * test_graph_topo.c
+ *
+ * Copyright 2017 - Philippe Proulx <pproulx@efficios.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; under version 2 of the License.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/assert.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#include "tap/tap.h"
+
+#define NR_TESTS       33
+
+enum event_type {
+       SRC_COMP_OUTPUT_PORT_CONNECTED,
+       SINK_COMP_INPUT_PORT_CONNECTED,
+       GRAPH_SRC_OUTPUT_PORT_ADDED,
+       GRAPH_SINK_INPUT_PORT_ADDED,
+       GRAPH_SRC_SINK_PORTS_CONNECTED,
+};
+
+enum test {
+       TEST_EMPTY_GRAPH,
+       TEST_SIMPLE,
+       TEST_SRC_PORT_CONNECTED_ERROR,
+       TEST_SINK_PORT_CONNECTED_ERROR,
+       TEST_SRC_ADDS_PORT_IN_PORT_CONNECTED,
+};
+
+struct event {
+       enum event_type type;
+
+       union {
+               struct {
+                       const bt_component *comp;
+                       const bt_port *self_port;
+                       const bt_port *other_port;
+               } src_comp_output_port_connected;
+
+               struct {
+                       const bt_component *comp;
+                       const bt_port *self_port;
+                       const bt_port *other_port;
+               } sink_comp_input_port_connected;
+
+               struct {
+                       const bt_component *comp;
+                       const bt_port *port;
+               } graph_src_output_port_added;
+
+               struct {
+                       const bt_component *comp;
+                       const bt_port *port;
+               } graph_sink_input_port_added;
+
+               struct {
+                       const bt_component *upstream_comp;
+                       const bt_component *downstream_comp;
+                       const bt_port *upstream_port;
+                       const bt_port *downstream_port;
+               } graph_src_sink_ports_connected;
+       } data;
+};
+
+static GArray *events;
+static bt_component_class_source *src_comp_class;
+static bt_component_class_sink *sink_comp_class;
+static enum test current_test;
+
+static
+void clear_events(void)
+{
+       g_array_set_size(events, 0);
+}
+
+static
+void append_event(struct event *event)
+{
+       g_array_append_val(events, *event);
+}
+
+static
+bool compare_events(struct event *ev_a, struct event *ev_b)
+{
+       if (ev_a->type != ev_b->type) {
+               return false;
+       }
+
+       switch (ev_a->type) {
+               case SRC_COMP_OUTPUT_PORT_CONNECTED:
+                       if (ev_a->data.src_comp_output_port_connected.comp !=
+                                       ev_b->data.src_comp_output_port_connected.comp) {
+                               return false;
+                       }
+
+                       if (ev_a->data.src_comp_output_port_connected.self_port !=
+                                       ev_b->data.src_comp_output_port_connected.self_port) {
+                               return false;
+                       }
+
+                       if (ev_a->data.src_comp_output_port_connected.other_port !=
+                                       ev_b->data.src_comp_output_port_connected.other_port) {
+                               return false;
+                       }
+                       break;
+               case SINK_COMP_INPUT_PORT_CONNECTED:
+                       if (ev_a->data.sink_comp_input_port_connected.comp !=
+                                       ev_b->data.sink_comp_input_port_connected.comp) {
+                               return false;
+                       }
+
+                       if (ev_a->data.sink_comp_input_port_connected.self_port !=
+                                       ev_b->data.sink_comp_input_port_connected.self_port) {
+                               return false;
+                       }
+
+                       if (ev_a->data.sink_comp_input_port_connected.other_port !=
+                                       ev_b->data.sink_comp_input_port_connected.other_port) {
+                               return false;
+                       }
+                       break;
+               case GRAPH_SRC_OUTPUT_PORT_ADDED:
+                       if (ev_a->data.graph_src_output_port_added.comp !=
+                                       ev_b->data.graph_src_output_port_added.comp) {
+                               return false;
+                       }
+
+                       if (ev_a->data.graph_src_output_port_added.port !=
+                                       ev_b->data.graph_src_output_port_added.port) {
+                               return false;
+                       }
+                       break;
+               case GRAPH_SINK_INPUT_PORT_ADDED:
+                       if (ev_a->data.graph_sink_input_port_added.comp !=
+                                       ev_b->data.graph_sink_input_port_added.comp) {
+                               return false;
+                       }
+
+                       if (ev_a->data.graph_sink_input_port_added.port !=
+                                       ev_b->data.graph_sink_input_port_added.port) {
+                               return false;
+                       }
+                       break;
+               case GRAPH_SRC_SINK_PORTS_CONNECTED:
+                       if (ev_a->data.graph_src_sink_ports_connected.upstream_comp !=
+                                       ev_b->data.graph_src_sink_ports_connected.upstream_comp) {
+                               return false;
+                       }
+
+                       if (ev_a->data.graph_src_sink_ports_connected.downstream_comp !=
+                                       ev_b->data.graph_src_sink_ports_connected.downstream_comp) {
+                               return false;
+                       }
+
+                       if (ev_a->data.graph_src_sink_ports_connected.upstream_port !=
+                                       ev_b->data.graph_src_sink_ports_connected.upstream_port) {
+                               return false;
+                       }
+
+                       if (ev_a->data.graph_src_sink_ports_connected.downstream_port !=
+                                       ev_b->data.graph_src_sink_ports_connected.downstream_port) {
+                               return false;
+                       }
+                       break;
+               default:
+                       abort();
+       }
+
+       return true;
+}
+
+static
+bool has_event(struct event *event)
+{
+       size_t i;
+
+       for (i = 0; i < events->len; i++) {
+               struct event *ev = &g_array_index(events, struct event, i);
+
+               if (compare_events(event, ev)) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static
+size_t event_pos(struct event *event)
+{
+       size_t i;
+
+       for (i = 0; i < events->len; i++) {
+               struct event *ev = &g_array_index(events, struct event, i);
+
+               if (compare_events(event, ev)) {
+                       return i;
+               }
+       }
+
+       return SIZE_MAX;
+}
+
+static
+bt_component_class_message_iterator_next_method_status src_iter_next(
+               bt_self_message_iterator *self_iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       return BT_COMPONENT_CLASS_MESSAGE_ITERATOR_NEXT_METHOD_STATUS_ERROR;
+}
+
+static
+bt_component_class_port_connected_method_status src_output_port_connected(
+               bt_self_component_source *self_comp,
+               bt_self_component_port_output *self_comp_port,
+               const bt_port_input *other_port)
+{
+       int ret;
+       struct event event = {
+               .type = SRC_COMP_OUTPUT_PORT_CONNECTED,
+               .data.src_comp_output_port_connected = {
+                       .comp = bt_self_component_as_component(
+                               bt_self_component_source_as_self_component(
+                                       self_comp)),
+                       .self_port = bt_self_component_port_as_port(
+                               bt_self_component_port_output_as_self_component_port(
+                                       self_comp_port)),
+                       .other_port = bt_port_input_as_port_const(other_port),
+               },
+       };
+
+       append_event(&event);
+
+       switch (current_test) {
+       case TEST_SRC_ADDS_PORT_IN_PORT_CONNECTED:
+               ret = bt_self_component_source_add_output_port(
+                       self_comp, "hello", NULL, NULL);
+               BT_ASSERT(ret == 0);
+               break;
+       case TEST_SRC_PORT_CONNECTED_ERROR:
+               return BT_COMPONENT_CLASS_PORT_CONNECTED_METHOD_STATUS_ERROR;
+       default:
+               break;
+       }
+
+       return BT_COMPONENT_CLASS_PORT_CONNECTED_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_port_connected_method_status sink_input_port_connected(
+               bt_self_component_sink *self_comp,
+               bt_self_component_port_input *self_comp_port,
+               const bt_port_output *other_port)
+{
+       struct event event = {
+               .type = SINK_COMP_INPUT_PORT_CONNECTED,
+               .data.sink_comp_input_port_connected = {
+                       .comp = bt_self_component_as_component(
+                               bt_self_component_sink_as_self_component(
+                                       self_comp)),
+                       .self_port = bt_self_component_port_as_port(
+                               bt_self_component_port_input_as_self_component_port(
+                                       self_comp_port)),
+                       .other_port = bt_port_output_as_port_const(other_port),
+               },
+       };
+
+       append_event(&event);
+
+       if (current_test == TEST_SINK_PORT_CONNECTED_ERROR) {
+               return BT_COMPONENT_CLASS_PORT_CONNECTED_METHOD_STATUS_ERROR;
+       } else {
+               return BT_COMPONENT_CLASS_PORT_CONNECTED_METHOD_STATUS_OK;
+       }
+}
+
+static
+bt_component_class_init_method_status src_init(
+       bt_self_component_source *self_comp,
+       const bt_value *params, void *init_method_data)
+{
+       int ret;
+
+       ret = bt_self_component_source_add_output_port(
+               self_comp, "out", NULL, NULL);
+       BT_ASSERT(ret == 0);
+       return BT_COMPONENT_CLASS_INIT_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_init_method_status sink_init(
+       bt_self_component_sink *self_comp,
+       const bt_value *params, void *init_method_data)
+{
+       int ret;
+
+       ret = bt_self_component_sink_add_input_port(self_comp,
+               "in", NULL, NULL);
+       BT_ASSERT(ret == 0);
+       return BT_COMPONENT_CLASS_INIT_METHOD_STATUS_OK;
+}
+
+static
+bt_component_class_sink_consume_method_status sink_consume(
+               bt_self_component_sink *self_comp)
+{
+       return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
+}
+
+static
+bt_graph_listener_func_status graph_src_output_port_added(
+               const bt_component_source *comp, const bt_port_output *port,
+               void *data)
+{
+       struct event event = {
+               .type = GRAPH_SRC_OUTPUT_PORT_ADDED,
+               .data.graph_src_output_port_added = {
+                       .comp = bt_component_source_as_component_const(comp),
+                       .port = bt_port_output_as_port_const(port),
+               },
+       };
+
+       append_event(&event);
+
+       return BT_GRAPH_LISTENER_FUNC_STATUS_OK;
+}
+
+static
+bt_graph_listener_func_status graph_sink_input_port_added(
+               const bt_component_sink *comp, const bt_port_input *port,
+               void *data)
+{
+       struct event event = {
+               .type = GRAPH_SINK_INPUT_PORT_ADDED,
+               .data.graph_sink_input_port_added = {
+                       .comp = bt_component_sink_as_component_const(comp),
+                       .port = bt_port_input_as_port_const(port),
+               },
+       };
+
+       append_event(&event);
+
+       return BT_GRAPH_LISTENER_FUNC_STATUS_OK;
+}
+
+static
+bt_graph_listener_func_status graph_src_sink_ports_connected(
+               const bt_component_source *upstream_comp,
+               const bt_component_sink *downstream_comp,
+               const bt_port_output *upstream_port,
+               const bt_port_input *downstream_port, void *data)
+{
+       struct event event = {
+               .type = GRAPH_SRC_SINK_PORTS_CONNECTED,
+               .data.graph_src_sink_ports_connected = {
+                       .upstream_comp =
+                               bt_component_source_as_component_const(upstream_comp),
+                               .downstream_comp =
+                               bt_component_sink_as_component_const(downstream_comp),
+                               .upstream_port =
+                               bt_port_output_as_port_const(upstream_port),
+                               .downstream_port =
+                               bt_port_input_as_port_const(downstream_port),
+               },
+       };
+
+       append_event(&event);
+
+       return BT_GRAPH_LISTENER_FUNC_STATUS_OK;
+}
+
+static
+void init_test(void)
+{
+       int ret;
+
+       src_comp_class = bt_component_class_source_create(
+               "src", src_iter_next);
+       BT_ASSERT(src_comp_class);
+       ret = bt_component_class_source_set_init_method(
+               src_comp_class, src_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_output_port_connected_method(
+               src_comp_class, src_output_port_connected);
+       BT_ASSERT(ret == 0);
+       sink_comp_class = bt_component_class_sink_create("sink",
+               sink_consume);
+       BT_ASSERT(sink_comp_class);
+       ret = bt_component_class_sink_set_init_method(sink_comp_class,
+               sink_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_sink_set_input_port_connected_method(
+               sink_comp_class, sink_input_port_connected);
+       BT_ASSERT(ret == 0);
+       events = g_array_new(FALSE, TRUE, sizeof(struct event));
+       BT_ASSERT(events);
+}
+
+static
+void fini_test(void)
+{
+       bt_component_class_source_put_ref(src_comp_class);
+       bt_component_class_sink_put_ref(sink_comp_class);
+       g_array_free(events, TRUE);
+}
+
+static
+const bt_component_source *create_src(bt_graph *graph)
+{
+       const bt_component_source *comp;
+       int ret;
+
+       ret = bt_graph_add_source_component(graph, src_comp_class,
+               "src-comp", NULL, BT_LOGGING_LEVEL_NONE, &comp);
+       BT_ASSERT(ret == 0);
+       return comp;
+}
+
+static
+const bt_component_sink *create_sink(bt_graph *graph)
+{
+       const bt_component_sink *comp;
+       int ret;
+
+       ret = bt_graph_add_sink_component(graph, sink_comp_class,
+               "sink-comp", NULL, BT_LOGGING_LEVEL_NONE, &comp);
+       BT_ASSERT(ret == 0);
+       return comp;
+}
+
+static
+bt_graph *create_graph(void)
+{
+       bt_graph *graph = bt_graph_create();
+       int ret;
+
+       BT_ASSERT(graph);
+       ret = bt_graph_add_source_component_output_port_added_listener(
+               graph, graph_src_output_port_added, NULL, NULL, NULL);
+       BT_ASSERT(ret >= 0);
+       ret = bt_graph_add_sink_component_input_port_added_listener(
+               graph, graph_sink_input_port_added, NULL, NULL, NULL);
+       BT_ASSERT(ret >= 0);
+       ret = bt_graph_add_source_sink_component_ports_connected_listener(
+               graph, graph_src_sink_ports_connected, NULL, NULL, NULL);
+       BT_ASSERT(ret >= 0);
+       return graph;
+}
+
+static
+void prepare_test(enum test test, const char *name)
+{
+       clear_events();
+       current_test = test;
+       diag("test: %s", name);
+}
+
+static
+void test_src_adds_port_in_port_connected(void)
+{
+       const bt_component_source *src;
+       const bt_component_sink *sink;
+       const bt_component *gsrc;
+       const bt_component *gsink;
+       bt_graph *graph;
+       const bt_port_output *src_def_port;
+       const bt_port_output *src_hello_port;
+       const bt_port_input *sink_def_port;
+       const bt_port *gsrc_def_port;
+       const bt_port *gsrc_hello_port;
+       const bt_port *gsink_def_port;
+       struct event event;
+       bt_graph_connect_ports_status status;
+       size_t src_port_connected_pos;
+       size_t sink_port_connected_pos;
+       size_t graph_ports_connected_pos;
+       size_t graph_port_added_src_pos;
+
+       prepare_test(TEST_SRC_ADDS_PORT_IN_PORT_CONNECTED,
+               "source adds port in port connected");
+       graph = create_graph();
+       BT_ASSERT(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
+       src_def_port = bt_component_source_borrow_output_port_by_name_const(src,
+                                                                           "out");
+       BT_ASSERT(src_def_port);
+       sink_def_port = bt_component_sink_borrow_input_port_by_name_const(sink,
+                                                                         "in");
+       BT_ASSERT(sink_def_port);
+       status = bt_graph_connect_ports(graph, src_def_port,
+               sink_def_port, NULL);
+       BT_ASSERT(status == 0);
+       src_hello_port = bt_component_source_borrow_output_port_by_name_const(src,
+                                                                             "hello");
+       BT_ASSERT(src_hello_port);
+       gsrc = bt_component_source_as_component_const(src);
+       gsink = bt_component_sink_as_component_const(sink);
+       gsrc_def_port = bt_port_output_as_port_const(src_def_port);
+       gsrc_hello_port = bt_port_output_as_port_const(src_hello_port);
+       gsink_def_port = bt_port_input_as_port_const(sink_def_port);
+
+       /* We're supposed to have 6 events */
+       ok(events->len == 6, "we have the expected number of events");
+
+       /* Source's port added */
+       event.type = GRAPH_SRC_OUTPUT_PORT_ADDED;
+       event.data.graph_src_output_port_added.comp = gsrc;
+       event.data.graph_src_output_port_added.port = gsrc_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_SINK_INPUT_PORT_ADDED;
+       event.data.graph_sink_input_port_added.comp = gsink;
+       event.data.graph_sink_input_port_added.port = gsink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
+
+       /* Source's port connected */
+       event.type = SRC_COMP_OUTPUT_PORT_CONNECTED;
+       event.data.src_comp_output_port_connected.comp = gsrc;
+       event.data.src_comp_output_port_connected.self_port = gsrc_def_port;
+       event.data.src_comp_output_port_connected.other_port = gsink_def_port;
+       ok(has_event(&event), "got the expected source's port connected event");
+       src_port_connected_pos = event_pos(&event);
+
+       /* Graph's port added (source) */
+       event.type = GRAPH_SRC_OUTPUT_PORT_ADDED;
+       event.data.graph_src_output_port_added.comp = gsrc;
+       event.data.graph_src_output_port_added.port = gsrc_hello_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source)");
+       graph_port_added_src_pos = event_pos(&event);
+
+       /* Sink's port connected */
+       event.type = SINK_COMP_INPUT_PORT_CONNECTED;
+       event.data.sink_comp_input_port_connected.comp = gsink;
+       event.data.sink_comp_input_port_connected.self_port = gsink_def_port;
+       event.data.sink_comp_input_port_connected.other_port = gsrc_def_port;
+       ok(has_event(&event), "got the expected sink's port connected event");
+       sink_port_connected_pos = event_pos(&event);
+
+       /* Graph's ports connected */
+       event.type = GRAPH_SRC_SINK_PORTS_CONNECTED;
+       event.data.graph_src_sink_ports_connected.upstream_comp = gsrc;
+       event.data.graph_src_sink_ports_connected.downstream_comp = gsink;
+       event.data.graph_src_sink_ports_connected.upstream_port = gsrc_def_port;
+       event.data.graph_src_sink_ports_connected.downstream_port = gsink_def_port;
+       ok(has_event(&event), "got the expected graph's ports connected event");
+       graph_ports_connected_pos = event_pos(&event);
+
+       /* Order of events */
+       ok(src_port_connected_pos < graph_ports_connected_pos,
+               "event order is good (1)");
+       ok(sink_port_connected_pos < graph_ports_connected_pos,
+               "event order is good (2)");
+       ok(src_port_connected_pos < graph_port_added_src_pos,
+               "event order is good (3)");
+       ok(graph_port_added_src_pos < graph_ports_connected_pos,
+               "event order is good (4)");
+
+       bt_component_source_put_ref(src);
+       bt_component_sink_put_ref(sink);
+       bt_graph_put_ref(graph);
+}
+
+static
+void test_simple(void)
+{
+       const bt_component_source *src;
+       const bt_component_sink *sink;
+       const bt_component *gsrc;
+       const bt_component *gsink;
+       bt_graph *graph;
+       const bt_port_output *src_def_port;
+       const bt_port_input *sink_def_port;
+       const bt_port *gsrc_def_port;
+       const bt_port *gsink_def_port;
+       struct event event;
+       bt_graph_connect_ports_status status;
+       size_t src_port_connected_pos;
+       size_t sink_port_connected_pos;
+       size_t graph_ports_connected_pos;
+
+       prepare_test(TEST_SIMPLE, "simple");
+       graph = create_graph();
+       BT_ASSERT(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
+       src_def_port = bt_component_source_borrow_output_port_by_name_const(src,
+                                                                           "out");
+       BT_ASSERT(src_def_port);
+       sink_def_port = bt_component_sink_borrow_input_port_by_name_const(sink,
+                                                                         "in");
+       BT_ASSERT(sink_def_port);
+       status = bt_graph_connect_ports(graph, src_def_port,
+               sink_def_port, NULL);
+       BT_ASSERT(status == 0);
+       gsrc = bt_component_source_as_component_const(src);
+       gsink = bt_component_sink_as_component_const(sink);
+       gsrc_def_port = bt_port_output_as_port_const(src_def_port);
+       gsink_def_port = bt_port_input_as_port_const(sink_def_port);
+
+       /* We're supposed to have 5 events */
+       ok(events->len == 5, "we have the expected number of events");
+
+       /* Source's port added */
+       event.type = GRAPH_SRC_OUTPUT_PORT_ADDED;
+       event.data.graph_src_output_port_added.comp = gsrc;
+       event.data.graph_src_output_port_added.port = gsrc_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_SINK_INPUT_PORT_ADDED;
+       event.data.graph_sink_input_port_added.comp = gsink;
+       event.data.graph_sink_input_port_added.port = gsink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
+
+       /* Source's port connected */
+       event.type = SRC_COMP_OUTPUT_PORT_CONNECTED;
+       event.data.src_comp_output_port_connected.comp = gsrc;
+       event.data.src_comp_output_port_connected.self_port = gsrc_def_port;
+       event.data.src_comp_output_port_connected.other_port = gsink_def_port;
+       ok(has_event(&event), "got the expected source's port connected event");
+       src_port_connected_pos = event_pos(&event);
+
+       /* Sink's port connected */
+       event.type = SINK_COMP_INPUT_PORT_CONNECTED;
+       event.data.sink_comp_input_port_connected.comp = gsink;
+       event.data.sink_comp_input_port_connected.self_port = gsink_def_port;
+       event.data.sink_comp_input_port_connected.other_port = gsrc_def_port;
+       ok(has_event(&event), "got the expected sink's port connected event");
+       sink_port_connected_pos = event_pos(&event);
+
+       /* Graph's ports connected */
+       event.type = GRAPH_SRC_SINK_PORTS_CONNECTED;
+       event.data.graph_src_sink_ports_connected.upstream_comp = gsrc;
+       event.data.graph_src_sink_ports_connected.downstream_comp = gsink;
+       event.data.graph_src_sink_ports_connected.upstream_port = gsrc_def_port;
+       event.data.graph_src_sink_ports_connected.downstream_port = gsink_def_port;
+       ok(has_event(&event), "got the expected graph's ports connected event");
+       graph_ports_connected_pos = event_pos(&event);
+
+       /* Order of events */
+       ok(src_port_connected_pos < graph_ports_connected_pos,
+               "event order is good (1)");
+       ok(sink_port_connected_pos < graph_ports_connected_pos,
+               "event order is good (2)");
+
+       bt_component_sink_put_ref(sink);
+       bt_graph_put_ref(graph);
+       bt_component_source_put_ref(src);
+}
+
+static
+void test_src_port_connected_error(void)
+{
+       const bt_component_source *src;
+       const bt_component_sink *sink;
+       const bt_component *gsrc;
+       const bt_component *gsink;
+       bt_graph *graph;
+       const bt_port_output *src_def_port;
+       const bt_port_input *sink_def_port;
+       const bt_port *gsrc_def_port;
+       const bt_port *gsink_def_port;
+       const bt_connection *conn = NULL;
+       struct event event;
+       bt_graph_connect_ports_status status;
+
+       prepare_test(TEST_SRC_PORT_CONNECTED_ERROR, "port connected error: source");
+       graph = create_graph();
+       BT_ASSERT(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
+       src_def_port = bt_component_source_borrow_output_port_by_name_const(src,
+                                                                           "out");
+       BT_ASSERT(src_def_port);
+       sink_def_port = bt_component_sink_borrow_input_port_by_name_const(sink,
+                                                                         "in");
+       BT_ASSERT(sink_def_port);
+       status = bt_graph_connect_ports(graph, src_def_port,
+               sink_def_port, &conn);
+       ok(status != BT_GRAPH_CONNECT_PORTS_STATUS_OK,
+               "bt_graph_connect_ports() returns an error");
+       ok(!conn, "returned connection is still NULL");
+       gsrc = bt_component_source_as_component_const(src);
+       gsink = bt_component_sink_as_component_const(sink);
+       gsrc_def_port = bt_port_output_as_port_const(src_def_port);
+       gsink_def_port = bt_port_input_as_port_const(sink_def_port);
+
+       /* We're supposed to have 3 events */
+       ok(events->len == 3, "we have the expected number of events");
+
+       /* Source's port added */
+       event.type = GRAPH_SRC_OUTPUT_PORT_ADDED;
+       event.data.graph_src_output_port_added.comp = gsrc;
+       event.data.graph_src_output_port_added.port = gsrc_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_SINK_INPUT_PORT_ADDED;
+       event.data.graph_sink_input_port_added.comp = gsink;
+       event.data.graph_sink_input_port_added.port = gsink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
+
+       /* Source's port connected */
+       event.type = SRC_COMP_OUTPUT_PORT_CONNECTED;
+       event.data.src_comp_output_port_connected.comp = gsrc;
+       event.data.src_comp_output_port_connected.self_port = gsrc_def_port;
+       event.data.src_comp_output_port_connected.other_port = gsink_def_port;
+       ok(has_event(&event), "got the expected source's port connected event");
+
+       bt_graph_put_ref(graph);
+       bt_component_sink_put_ref(sink);
+       bt_component_source_put_ref(src);
+       bt_connection_put_ref(conn);
+}
+
+static
+void test_sink_port_connected_error(void)
+{
+       const bt_component_source *src;
+       const bt_component_sink *sink;
+       const bt_component *gsrc;
+       const bt_component *gsink;
+       bt_graph *graph;
+       const bt_port_output *src_def_port;
+       const bt_port_input *sink_def_port;
+       const bt_port *gsrc_def_port;
+       const bt_port *gsink_def_port;
+       const bt_connection *conn = NULL;
+       struct event event;
+       bt_graph_connect_ports_status status;
+
+       prepare_test(TEST_SINK_PORT_CONNECTED_ERROR, "port connected error: sink");
+       graph = create_graph();
+       BT_ASSERT(graph);
+       src = create_src(graph);
+       sink = create_sink(graph);
+       src_def_port = bt_component_source_borrow_output_port_by_name_const(src,
+                                                                           "out");
+       BT_ASSERT(src_def_port);
+       sink_def_port = bt_component_sink_borrow_input_port_by_name_const(sink,
+                                                                         "in");
+       BT_ASSERT(sink_def_port);
+       status = bt_graph_connect_ports(graph, src_def_port,
+               sink_def_port, &conn);
+       ok(status != BT_GRAPH_CONNECT_PORTS_STATUS_OK,
+               "bt_graph_connect_ports() returns an error");
+       ok(!conn, "returned connection is still NULL");
+       gsrc = bt_component_source_as_component_const(src);
+       gsink = bt_component_sink_as_component_const(sink);
+       gsrc_def_port = bt_port_output_as_port_const(src_def_port);
+       gsink_def_port = bt_port_input_as_port_const(sink_def_port);
+
+       /* We're supposed to have 4 events */
+       ok(events->len == 4, "we have the expected number of events");
+
+       /* Source's port added */
+       event.type = GRAPH_SRC_OUTPUT_PORT_ADDED;
+       event.data.graph_src_output_port_added.comp = gsrc;
+       event.data.graph_src_output_port_added.port = gsrc_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for source, initial)");
+
+       /* Sink's port added */
+       event.type = GRAPH_SINK_INPUT_PORT_ADDED;
+       event.data.graph_sink_input_port_added.comp = gsink;
+       event.data.graph_sink_input_port_added.port = gsink_def_port;
+       ok(has_event(&event), "got the expected graph's port added event (for sink, initial)");
+
+       /* Source's port connected */
+       event.type = SRC_COMP_OUTPUT_PORT_CONNECTED;
+       event.data.src_comp_output_port_connected.comp = gsrc;
+       event.data.src_comp_output_port_connected.self_port = gsrc_def_port;
+       event.data.src_comp_output_port_connected.other_port = gsink_def_port;
+       ok(has_event(&event), "got the expected source's port connected event");
+
+       /* Sink's port connected */
+       event.type = SINK_COMP_INPUT_PORT_CONNECTED;
+       event.data.sink_comp_input_port_connected.comp = gsink;
+       event.data.sink_comp_input_port_connected.self_port = gsink_def_port;
+       event.data.sink_comp_input_port_connected.other_port = gsrc_def_port;
+       ok(has_event(&event), "got the expected sink's port connected event");
+
+       bt_connection_put_ref(conn);
+       bt_graph_put_ref(graph);
+       bt_component_sink_put_ref(sink);
+       bt_component_source_put_ref(src);
+}
+
+static
+void test_empty_graph(void)
+{
+       bt_graph *graph;
+
+       prepare_test(TEST_EMPTY_GRAPH, "empty graph");
+       graph = create_graph();
+       ok(events->len == 0, "empty graph generates no events");
+       bt_graph_put_ref(graph);
+}
+
+int main(int argc, char **argv)
+{
+       plan_tests(NR_TESTS);
+       init_test();
+       test_empty_graph();
+       test_simple();
+       test_src_port_connected_error();
+       test_sink_port_connected_error();
+       test_src_adds_port_in_port_connected();
+       fini_test();
+       return exit_status();
+}
This page took 0.0442 seconds and 4 git commands to generate.