/* * * Embedded Linux library * * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include "ell/dbus-private.h" struct l_dbus_interface *interface; static bool callback_called = false; static char *dummy_data = "Foobar"; struct introspect_test { const char *name; const char *expected_xml; }; static const struct introspect_test frobate_test = { .name = "Frobate", .expected_xml = "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n", }; static const struct introspect_test bazify_test = { .name = "Bazify", .expected_xml = "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n", }; static const struct introspect_test mogrify_test = { .name = "Mogrify", .expected_xml = "\t\t\n" "\t\t\t\n" "\t\t\n", }; static const struct introspect_test changed_test = { .name = "Changed", .expected_xml = "\t\t\n" "\t\t\t\n" "\t\t\n", }; static const struct introspect_test bar_test = { .name = "Bar", .expected_xml = "\t\t\n", }; static const struct introspect_test interface_test = { .name = "", .expected_xml = "\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\n" "\t\n", }; static void test_introspect_method(const void *test_data) { const struct introspect_test *test = test_data; struct _dbus_method *method; struct l_string *buf; char *xml; method = _dbus_interface_find_method(interface, test->name); assert(method); buf = l_string_new(0); _dbus_method_introspection(method, buf); xml = l_string_unwrap(buf); assert(!strcmp(test->expected_xml, xml)); l_free(xml); } static void test_introspect_signal(const void *test_data) { const struct introspect_test *test = test_data; struct _dbus_signal *signal; struct l_string *buf; char *xml; signal = _dbus_interface_find_signal(interface, test->name); assert(signal); buf = l_string_new(0); _dbus_signal_introspection(signal, buf); xml = l_string_unwrap(buf); assert(!strcmp(test->expected_xml, xml)); l_free(xml); } static void test_introspect_property(const void *test_data) { const struct introspect_test *test = test_data; struct _dbus_property *property; struct l_string *buf; char *xml; property = _dbus_interface_find_property(interface, test->name); assert(property); buf = l_string_new(0); _dbus_property_introspection(property, buf); xml = l_string_unwrap(buf); assert(!strcmp(test->expected_xml, xml)); l_free(xml); } static void test_introspect_interface(const void *test_data) { const struct introspect_test *test = test_data; struct l_string *buf; char *xml; buf = l_string_new(0); _dbus_interface_introspection(interface, buf); xml = l_string_unwrap(buf); assert(!strcmp(test->expected_xml, xml)); l_free(xml); } static void test_dbus_object_tree_1(const void *test_data) { struct _dbus_object_tree *tree; struct object_node *leaf1, *leaf2, *leaf3; struct object_node *tmp; tree = _dbus_object_tree_new(); assert(tree); leaf1 = _dbus_object_tree_makepath(tree, "/foo/bar/baz"); leaf2 = _dbus_object_tree_makepath(tree, "/foo/bar/ble"); leaf3 = _dbus_object_tree_makepath(tree, "/foo/bee/boo"); tmp = _dbus_object_tree_lookup(tree, "/foo"); assert(tmp); tmp = _dbus_object_tree_lookup(tree, "/foo/bar/baz"); assert(tmp); assert(tmp == leaf1); tmp = _dbus_object_tree_lookup(tree, "/foo/bar/ble"); assert(tmp); assert(tmp == leaf2); tmp = _dbus_object_tree_lookup(tree, "/foo/bee/boo"); assert(tmp); assert(tmp == leaf3); tmp = _dbus_object_tree_lookup(tree, "/foobar"); assert(!tmp); tmp = _dbus_object_tree_lookup(tree, "/foo/bee"); assert(tmp); _dbus_object_tree_prune_node(leaf3); tmp = _dbus_object_tree_lookup(tree, "/foo/bee"); assert(!tmp); tmp = _dbus_object_tree_lookup(tree, "/foo/bar"); assert(tmp); _dbus_object_tree_prune_node(leaf2); tmp = _dbus_object_tree_lookup(tree, "/foo/bar"); assert(tmp); _dbus_object_tree_prune_node(leaf1); tmp = _dbus_object_tree_lookup(tree, "/foo/bar"); assert(!tmp); tmp = _dbus_object_tree_lookup(tree, "/foo"); assert(!tmp); tmp = _dbus_object_tree_lookup(tree, "/"); assert(tmp); _dbus_object_tree_free(tree); } static void setup_dummy_interface(struct l_dbus_interface *iface) { } static void interface_destroy(void *data) { bool *destroyed = data; *destroyed = true; } static void test_dbus_object_tree_2(const void *test_data) { struct _dbus_object_tree *tree; bool destroyed[2] = { false, false }; tree = _dbus_object_tree_new(); assert(tree); assert(_dbus_object_tree_new_object(tree, "/foo", NULL, NULL)); assert(_dbus_object_tree_new_object(tree, "/foo/bar/baz", NULL, NULL)); assert(_dbus_object_tree_lookup(tree, "/foo")); assert(_dbus_object_tree_lookup(tree, "/foo/bar")); assert(_dbus_object_tree_lookup(tree, "/foo/bar/baz")); assert(_dbus_object_tree_register_interface(tree, "org.example", setup_dummy_interface, interface_destroy, false)); assert(_dbus_object_tree_add_interface(tree, "/foo", "org.example", &destroyed[0])); assert(!_dbus_object_tree_add_interface(tree, "/foo", "org.other", NULL)); assert(_dbus_object_tree_add_interface(tree, "/foo/bar/baz", "org.example", &destroyed[1])); assert(!_dbus_object_tree_remove_interface(tree, "/foo", "org.other")); assert(_dbus_object_tree_remove_interface(tree, "/foo", "org.example")); assert(destroyed[0]); assert(_dbus_object_tree_object_destroy(tree, "/foo")); assert(!_dbus_object_tree_object_destroy(tree, "/foo/bar")); assert(_dbus_object_tree_lookup(tree, "/foo")); assert(_dbus_object_tree_lookup(tree, "/foo/bar")); assert(_dbus_object_tree_lookup(tree, "/foo/bar/baz")); destroyed[0] = false; assert(_dbus_object_tree_add_interface(tree, "/foo", "org.example", &destroyed[0])); assert(_dbus_object_tree_object_destroy(tree, "/foo/bar/baz")); assert(_dbus_object_tree_lookup(tree, "/foo")); assert(!_dbus_object_tree_lookup(tree, "/foo/bar")); assert(!_dbus_object_tree_lookup(tree, "/foo/bar/baz")); assert(_dbus_object_tree_object_destroy(tree, "/foo")); assert(destroyed[0] && destroyed[1]); assert(!_dbus_object_tree_lookup(tree, "/foo")); destroyed[0] = false; assert(_dbus_object_tree_add_interface(tree, "/foo", "org.example", &destroyed[0])); assert(!_dbus_object_tree_unregister_interface(tree, "org.other")); assert(_dbus_object_tree_unregister_interface(tree, "org.example")); assert(destroyed[0]); _dbus_object_tree_free(tree); } #define TEST_3_OBJ_COUNT 20000 static void test_dbus_object_tree_3(const void *test_data) { struct _dbus_object_tree *tree; char path[50]; struct l_hashmap *paths; unsigned int count = 0; struct l_dbus_message *message, *reply; struct l_dbus_message_iter objects, interfaces; const char *obj_path; tree = _dbus_object_tree_new(); assert(tree); assert(_dbus_object_tree_register_interface(tree, "org.example", setup_dummy_interface, NULL, false)); srand48(50); paths = l_hashmap_string_new(); while (count < TEST_3_OBJ_COUNT) { unsigned int len = 0; unsigned int subpath_len = 0; bool repeat; /* Generate a random legal path composed of a, b and / chars */ path[len++] = '/'; while (len < sizeof(path) - 1) { const char *allowed; char ch; if (subpath_len) allowed = "aabb/E"; else /* At least one letter required after a / */ allowed = "ab"; ch = allowed[lrand48() % strlen(allowed)]; if (ch == 'E') break; else if (ch == '/') subpath_len = 0; else subpath_len++; path[len++] = ch; } /* Last character can't be a / */ if (path[len - 1] == '/') len--; path[len] = '\0'; repeat = l_hashmap_lookup(paths, path) != NULL; assert(_dbus_object_tree_add_interface(tree, path, "org.example", NULL) == !repeat); if (!repeat) { l_hashmap_insert(paths, path, path); count++; } } assert(_dbus_object_tree_add_interface(tree, "/", L_DBUS_INTERFACE_OBJECT_MANAGER, NULL)); l_hashmap_insert(paths, "/", path); message = _dbus_message_new_method_call(1, "org.example", "/", L_DBUS_INTERFACE_OBJECT_MANAGER, "GetManagedObjects"); l_dbus_message_set_arguments(message, ""); _dbus_message_set_serial(message, 0); reply = _dbus_object_tree_get_objects(tree, NULL, "/", message); assert(reply); assert(!l_dbus_message_get_error(reply, NULL, NULL)); assert(l_dbus_message_get_arguments(reply, "a{oa{sa{sv}}}", &objects)); while (l_dbus_message_iter_next_entry(&objects, &obj_path, &interfaces)) assert(l_hashmap_remove(paths, obj_path)); l_dbus_message_unref(message); l_dbus_message_unref(reply); assert(l_hashmap_isempty(paths)); l_hashmap_destroy(paths, NULL); assert(_dbus_object_tree_remove_interface(tree, "/", L_DBUS_INTERFACE_OBJECT_MANAGER)); assert(_dbus_object_tree_unregister_interface(tree, "org.example")); _dbus_object_tree_free(tree); } static struct l_dbus_message *get_modems_callback(struct l_dbus *dbus, struct l_dbus_message *message, void *user_data) { assert(user_data == dummy_data); callback_called = true; return NULL; } static void build_manager_interface(struct l_dbus_interface *iface) { l_dbus_interface_method(iface, "GetModems", 0, get_modems_callback, "a(oa{sv})", "", "modems"); l_dbus_interface_signal(iface, "ModemAdded", 0, "oa{sv}", "path", "properties"); l_dbus_interface_signal(iface, "ModemRemoved", 0, "o", "path"); } static const char *ofono_manager_introspection = "\n" "\n" "\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n\t\n" "\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\n" "\t\t\n" "\t\t\t\n" "\t\t\n\t\n" "\t\n" "\n"; static void test_dbus_object_tree_introspection(const void *test_data) { struct _dbus_object_tree *tree; struct l_string *buf; char *xml; tree = _dbus_object_tree_new(); _dbus_object_tree_register_interface(tree, "org.ofono.Manager", build_manager_interface, NULL, false); _dbus_object_tree_add_interface(tree, "/", "org.ofono.Manager", NULL); _dbus_object_tree_makepath(tree, "/phonesim"); buf = l_string_new(1024); _dbus_object_tree_introspect(tree, "/", buf); xml = l_string_unwrap(buf); assert(!strcmp(ofono_manager_introspection, xml)); l_free(xml); _dbus_object_tree_free(tree); } static void test_dbus_object_tree_dispatch(const void *test_data) { struct _dbus_object_tree *tree; struct l_dbus_message *message; tree = _dbus_object_tree_new(); _dbus_object_tree_register_interface(tree, "org.ofono.Manager", build_manager_interface, NULL, false); _dbus_object_tree_add_interface(tree, "/", "org.ofono.Manager", dummy_data); message = _dbus_message_new_method_call(1, "org.ofono", "/", "org.ofono.Manager", "GetModems"); l_dbus_message_set_arguments(message, ""); _dbus_object_tree_dispatch(tree, NULL, message); assert(callback_called); l_dbus_message_unref(message); _dbus_object_tree_free(tree); } static bool test_property_getter(struct l_dbus *dbus, struct l_dbus_message *message, struct l_dbus_message_builder *builder, void *if_user_data) { return true; } static struct l_dbus_message *test_property_setter(struct l_dbus *dbus, struct l_dbus_message *message, struct l_dbus_message_iter *new_value, l_dbus_property_complete_cb_t complete, void *user_data) { return NULL; } int main(int argc, char *argv[]) { int ret; interface = _dbus_interface_new("org.freedesktop.SampleInterface"); l_test_init(&argc, &argv); l_dbus_interface_method(interface, "Frobate", L_DBUS_METHOD_FLAG_DEPRECATED, NULL, "sa{us}", "i", "bar", "baz", "foo"); l_dbus_interface_method(interface, "Bazify", 0, NULL, "v", "(iiu)", "bar", "bar"); l_dbus_interface_method(interface, "Mogrify", 0, NULL, "", "(iiav)", "bar"); l_dbus_interface_signal(interface, "Changed", 0, "b", "new_value"); l_dbus_interface_property(interface, "Bar", 0, "y", test_property_getter, test_property_setter); l_test_add("Test Frobate Introspection", test_introspect_method, &frobate_test); l_test_add("Test Bazify Introspection", test_introspect_method, &bazify_test); l_test_add("Test Mogrify Introspection", test_introspect_method, &mogrify_test); l_test_add("Test Changed Introspection", test_introspect_signal, &changed_test); l_test_add("Test Bar Property Introspection", test_introspect_property, &bar_test); l_test_add("Test Interface Introspection", test_introspect_interface, &interface_test); l_test_add("_dbus_object_tree Sanity Tests 1", test_dbus_object_tree_1, NULL); l_test_add("_dbus_object_tree Sanity Tests 2", test_dbus_object_tree_2, NULL); l_test_add("_dbus_object_tree Sanity Tests 3", test_dbus_object_tree_3, NULL); l_test_add("_dbus_object_tree Introspection", test_dbus_object_tree_introspection, NULL); l_test_add("_dbus_object_tree Dispatcher", test_dbus_object_tree_dispatch, NULL); ret = l_test_run(); _dbus_interface_free(interface); return ret; }