diff --git a/src/busctl/busctl-introspect.c b/src/busctl/busctl-introspect.c index 4dbb11f15b..9fbe9ebb5e 100644 --- a/src/busctl/busctl-introspect.c +++ b/src/busctl/busctl-introspect.c @@ -228,7 +228,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth (t == XML_TAG_CLOSE && streq_ptr(name, "node"))) { if (context->ops->on_path) { - r = context->ops->on_path(node_path ? node_path : np, context->userdata); + r = context->ops->on_path(node_path ?: np, context->userdata); if (r < 0) return r; } @@ -250,7 +250,6 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth if (name[0] == '/') node_path = TAKE_PTR(name); else { - node_path = path_join(prefix, name); if (!node_path) return log_oom(); diff --git a/src/busctl/busctl-introspect.h b/src/busctl/busctl-introspect.h index 1a045bea1d..720a0df79a 100644 --- a/src/busctl/busctl-introspect.h +++ b/src/busctl/busctl-introspect.h @@ -2,6 +2,7 @@ #pragma once #include +#include typedef struct XMLIntrospectOps { int (*on_path)(const char *path, void *userdata); diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 27210e9389..30a86234d9 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -464,14 +464,6 @@ static int tree_one(sd_bus *bus, const char *service) { if (r < 0) return log_oom(); - done = set_new(&string_hash_ops_free); - if (!done) - return log_oom(); - - failed = set_new(&string_hash_ops_free); - if (!failed) - return log_oom(); - for (;;) { _cleanup_free_ char *p = NULL; int q; @@ -488,7 +480,7 @@ static int tree_one(sd_bus *bus, const char *service) { if (q < 0 && r >= 0) r = q; - q = set_consume(q < 0 ? failed : done, TAKE_PTR(p)); + q = set_ensure_consume(q < 0 ? &failed : &done, &string_hash_ops_free, TAKE_PTR(p)); assert(q != 0); if (q < 0) return log_oom(); diff --git a/src/busctl/meson.build b/src/busctl/meson.build index aacd0b270d..f463436fab 100644 --- a/src/busctl/meson.build +++ b/src/busctl/meson.build @@ -4,3 +4,9 @@ busctl_sources = files( 'busctl-introspect.c', 'busctl-introspect.h', 'busctl.c') + +tests += [ + [['src/busctl/test-busctl-introspect.c', + 'src/busctl/busctl-introspect.c', + 'src/busctl/busctl-introspect.h']], +] diff --git a/src/busctl/test-busctl-introspect.c b/src/busctl/test-busctl-introspect.c new file mode 100644 index 0000000000..862a92a0e2 --- /dev/null +++ b/src/busctl/test-busctl-introspect.c @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "busctl-introspect.h" +#include "set.h" +#include "strv.h" +#include "tests.h" + +static const char *xml_root = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static const char *xml_org = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static const char *xml_org_freedesktop = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static const char *xml_org_freedesktop_LogControl1 = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static const char *xml_org_freedesktop_network1 = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static const char *xml_org_freedesktop_network1_network = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static const char *xml_org_freedesktop_network1_network_unsigned = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +static int on_path(const char *path, void *userdata) { + Set *paths = userdata; + + assert_se(paths); + assert_se(set_put_strdup(&paths, path) >= 0); + + return 0; +} + +static void test_introspect_on_path(void) { + static const XMLIntrospectOps ops = { + .on_path = on_path, + }; + _cleanup_strv_free_ char **expected = NULL; + _cleanup_set_free_ Set *paths = NULL; + _cleanup_free_ char **l = NULL; + + log_info("/* %s */", __func__); + + assert_se(set_put_strdup(&paths, "/") > 0); + + log_debug("/* parse_xml_introspect(\"/\") */"); + assert_se(parse_xml_introspect("/", xml_root, &ops, paths) >= 0); + log_debug("/* parse_xml_introspect(\"/org\") */"); + assert_se(parse_xml_introspect("/org", xml_org, &ops, paths) >= 0); + log_debug("/* parse_xml_introspect(\"/org/freedesktop\") */"); + assert_se(parse_xml_introspect("/org/freedesktop", xml_org_freedesktop, &ops, paths) >= 0); + log_debug("/* parse_xml_introspect(\"/org/freedesktop/LogControl1\") */"); + assert_se(parse_xml_introspect("/org/freedesktop/LogControl1", xml_org_freedesktop_LogControl1, &ops, paths) >= 0); + log_debug("/* parse_xml_introspect(\"/org/freedesktop/network1\") */"); + assert_se(parse_xml_introspect("/org/freedesktop/network1", xml_org_freedesktop_network1, &ops, paths) >= 0); + log_debug("/* parse_xml_introspect(\"/org/freedesktop/network1/network\") */"); + assert_se(parse_xml_introspect("/org/freedesktop/network1/network", xml_org_freedesktop_network1_network, &ops, paths) >= 0); + for (unsigned i = 0; i <= 20; i++) { + _cleanup_free_ char *path = NULL; + + assert_se(asprintf(&path, "/org/freedesktop/network1/network/%u", i) >= 0); + log_debug("/* parse_xml_introspect(\"%s\") */", path); + assert_se(parse_xml_introspect(path, xml_org_freedesktop_network1_network_unsigned, &ops, paths) >= 0); + } + + assert_se(l = set_get_strv(paths)); + strv_sort(l); + + assert_se(strv_extend(&expected, "/") >= 0); + assert_se(strv_extend(&expected, "/org") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/LogControl1") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/0") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/0/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/1") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/1/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/2") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/2/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/3") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/3/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/4") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/4/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/5") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/5/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/6") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/6/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/7") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/7/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/8") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/8/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/9") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/9/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/10") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/10/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/11") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/11/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/12") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/12/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/13") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/13/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/14") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/14/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/15") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/15/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/16") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/16/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/17") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/17/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/18") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/18/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/19") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/19/hoge") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/20") >= 0); + assert_se(strv_extend(&expected, "/org/freedesktop/network1/network/20/hoge") >= 0); + + strv_sort(expected); + assert_se(strv_equal(l, expected)); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + test_introspect_on_path(); + + return 0; +}