blob: 029d71c036f1fcb9acd9a177b748327686f9ac8f [file] [log] [blame]
/*
*
* Embedded Linux library
*
* Copyright (C) 2011-2015 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 <config.h>
#endif
#include <stdlib.h>
#include <assert.h>
#include <ell/ell.h>
#include "ell/dbus-private.h"
#include "ell/private.h"
#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
static void test_rule_to_str(const void *test_data)
{
static const struct _dbus_filter_condition rule1[] = {
{ L_DBUS_MATCH_TYPE, "signal" },
{ L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS },
{ L_DBUS_MATCH_PATH, DBUS_PATH_DBUS },
{ L_DBUS_MATCH_INTERFACE, DBUS_INTERFACE_DBUS },
{ L_DBUS_MATCH_MEMBER, "NameOwnerChanged" },
{ L_DBUS_MATCH_ARGUMENT(0), ":1.101" }
};
static const char *expected1 = "type='signal',"
"sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus',"
"interface='org.freedesktop.DBus',"
"member='NameOwnerChanged',"
"arg0=':1.101'";
static const struct _dbus_filter_condition rule2[] = {
{ L_DBUS_MATCH_ARGUMENT(0), "'" },
{ L_DBUS_MATCH_ARGUMENT(1), "\\" },
{ L_DBUS_MATCH_ARGUMENT(2), "," },
{ L_DBUS_MATCH_ARGUMENT(3), "\\\\" }
};
static const char *expected2 =
"arg0=''\\''',arg1='\\',arg2=',',arg3='\\\\'";
char *str;
str = _dbus_filter_rule_to_str(rule1, L_ARRAY_SIZE(rule1));
assert(str && !strcmp(str, expected1));
l_free(str);
str = _dbus_filter_rule_to_str(rule2, L_ARRAY_SIZE(rule2));
assert(str && !strcmp(str, expected2));
l_free(str);
}
struct l_dbus {
};
struct filter_test_state {
struct l_dbus dbus;
const struct _dbus_filter_condition *expected_rule;
int expected_rule_len;
unsigned int expected_id, new_id;
int calls[5];
};
static void rule_compare(const struct _dbus_filter_condition *a, int len_a,
const struct _dbus_filter_condition *b, int len_b)
{
int i, j;
bool matched[len_a];
assert(len_a == len_b);
for (i = 0; i < len_a; i++)
matched[i] = false;
for (i = 0; i < len_a; i++) {
for (j = 0; j < len_a; j++)
if (!matched[j] && a[i].type == b[j].type &&
!strcmp(a[i].value, b[j].value))
break;
assert(j < len_a);
matched[j] = true;
}
}
static bool test_add_match(struct l_dbus *dbus, unsigned int id,
const struct _dbus_filter_condition *rule,
int rule_len)
{
struct filter_test_state *test =
l_container_of(dbus, struct filter_test_state, dbus);
assert(test->expected_rule);
rule_compare(test->expected_rule, test->expected_rule_len,
rule, rule_len);
test->new_id = id;
test->expected_rule = NULL;
return true;
}
static bool test_remove_match(struct l_dbus *dbus, unsigned int id)
{
struct filter_test_state *test =
l_container_of(dbus, struct filter_test_state, dbus);
assert(test->expected_id == id && id);
test->expected_id = 0;
return true;
}
static void test_rule1_cb(struct l_dbus_message *message, void *user_data)
{
struct filter_test_state *test = user_data;
test->calls[0]++;
}
static void test_rule2_cb(struct l_dbus_message *message, void *user_data)
{
struct filter_test_state *test = user_data;
test->calls[1]++;
}
static void test_rule3_cb(struct l_dbus_message *message, void *user_data)
{
struct filter_test_state *test = user_data;
test->calls[2]++;
}
static void test_rule4_cb(struct l_dbus_message *message, void *user_data)
{
struct filter_test_state *test = user_data;
test->calls[3]++;
}
static void test_rule5_cb(struct l_dbus_message *message, void *user_data)
{
struct filter_test_state *test = user_data;
test->calls[4]++;
}
static void test_filter_tree(const void *test_data)
{
struct _dbus_filter *filter;
struct filter_test_state test = { .calls = { 0, 0, 0, 0 } };
static const struct _dbus_filter_ops filter_ops = {
.skip_register = true,
.add_match = test_add_match,
.remove_match = test_remove_match,
};
static const struct _dbus_filter_condition rule123[] = {
{ L_DBUS_MATCH_TYPE, "signal" },
{ L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS },
{ L_DBUS_MATCH_PATH, DBUS_PATH_DBUS },
{ L_DBUS_MATCH_INTERFACE, DBUS_INTERFACE_DBUS },
{ L_DBUS_MATCH_MEMBER, "NameOwnerChanged" },
{ L_DBUS_MATCH_ARGUMENT(0), "org.test" }
};
static const struct _dbus_filter_condition rule45[] = {
{ L_DBUS_MATCH_TYPE, "signal" },
{ L_DBUS_MATCH_PATH, "/" },
{ L_DBUS_MATCH_SENDER, "org.foo" },
};
unsigned int id1, id2, id3, id4, id5, internal_id1, internal_id4;
struct l_dbus_message *message;
filter = _dbus_filter_new(&test.dbus, &filter_ops, NULL);
assert(filter);
test.expected_rule = rule123;
test.expected_rule_len = 2;
id1 = _dbus_filter_add_rule(filter, rule123, 2, test_rule1_cb, &test);
assert(id1);
assert(!test.expected_rule);
internal_id1 = test.new_id;
id2 = _dbus_filter_add_rule(filter, rule123, 4, test_rule2_cb, &test);
id3 = _dbus_filter_add_rule(filter, rule123, 6, test_rule3_cb, &test);
assert(id2 && id3 && id2 != id1 && id3 != id1 && id3 != id2);
test.expected_rule = rule45;
test.expected_rule_len = 2;
id4 = _dbus_filter_add_rule(filter, rule45, 2, test_rule4_cb, &test);
assert(id4 && id4 != id1 && id4 != id2 && id4 != id3);
assert(!test.expected_rule);
internal_id4 = test.new_id;
id5 = _dbus_filter_add_rule(filter, rule45, 3, test_rule5_cb, &test);
assert(id5 && id5 != id1 && id5 != id2 && id5 != id3 && id5 != id4);
assert(test.calls[0] == 0 && test.calls[1] == 0 &&
test.calls[2] == 0 && test.calls[3] == 0 &&
test.calls[4] == 0);
message = _dbus_message_new_signal(2, DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"NameOwnerChanged");
l_dbus_message_set_arguments(message, "sss", "org.test",
"", ":1.101");
_dbus_message_set_sender(message, DBUS_SERVICE_DBUS);
_dbus_filter_dispatch(message, filter);
_dbus_message_set_sender(message, NULL);
l_dbus_message_unref(message);
message = _dbus_message_new_signal(2, DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"NameOwnerChanged");
l_dbus_message_set_arguments(message, "");
_dbus_message_set_sender(message, DBUS_SERVICE_DBUS);
_dbus_filter_dispatch(message, filter);
_dbus_message_set_sender(message, NULL);
l_dbus_message_unref(message);
message = _dbus_message_new_signal(2, DBUS_PATH_DBUS, "foo", "Bar");
l_dbus_message_set_arguments(message, "");
_dbus_message_set_sender(message, DBUS_SERVICE_DBUS);
_dbus_filter_dispatch(message, filter);
_dbus_message_set_sender(message, NULL);
l_dbus_message_unref(message);
message = _dbus_message_new_signal(2, "/", "foo", "Bar");
l_dbus_message_set_arguments(message, "");
_dbus_message_set_sender(message, "org.foo");
_dbus_filter_dispatch(message, filter);
_dbus_message_set_sender(message, "org.bar");
_dbus_filter_dispatch(message, filter);
_dbus_message_set_sender(message, NULL);
l_dbus_message_unref(message);
assert(test.calls[0] == 3 && test.calls[1] == 2 &&
test.calls[2] == 1 && test.calls[3] == 2 &&
test.calls[4] == 1);
test.expected_id = 0;
assert(_dbus_filter_remove_rule(filter, id2));
assert(_dbus_filter_remove_rule(filter, id1));
assert(_dbus_filter_remove_rule(filter, id5));
test.expected_id = internal_id4;
assert(_dbus_filter_remove_rule(filter, id4));
assert(!test.expected_id);
test.expected_id = internal_id1;
assert(_dbus_filter_remove_rule(filter, id3));
assert(!test.expected_id);
_dbus_filter_free(filter);
assert(test.calls[0] == 3 && test.calls[1] == 2 &&
test.calls[2] == 1 && test.calls[3] == 2 &&
test.calls[4] == 1);
}
int main(int argc, char *argv[])
{
l_test_init(&argc, &argv);
l_test_add("_dbus_filter_rule_to_str", test_rule_to_str, NULL);
l_test_add("DBus filter tree", test_filter_tree, NULL);
return l_test_run();
}