From: Lennart Poettering Date: Tue, 4 Nov 2025 09:35:00 +0000 (+0100) Subject: varlink-idl: add infra to test our enum parsers against varlink IDL enums X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=030f239a198de34c06aeb6b8680176102ed684d2;p=thirdparty%2Fsystemd.git varlink-idl: add infra to test our enum parsers against varlink IDL enums In many cases we want to expose enums for which we have the usual xyz_to_string()/xyz_from_string() via Varlink as enums. Let's add some infra to test the tables against each other, to automatically detect when they deviate. In order to implement this properly, let's export/introduce clean json_underscorefy()/json_dashify(), for dealing with the fact that our enums usually use dash separates ames, but Varlink doesn't allow that. (This does not add the test cases for all enum types we expose right now, but only adds the general infra). --- diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h index c2d353476d2..f4b9b4e7e11 100644 --- a/src/libsystemd/sd-json/json-util.h +++ b/src/libsystemd/sd-json/json-util.h @@ -64,11 +64,11 @@ struct json_variant_foreach_state { type cc = func(sd_json_variant_string(variant)); \ if (cc < 0) { \ /* Maybe this enum is recognizable if we replace "_" (i.e. Varlink syntax) with "-" (how we usually prefer it). */ \ - _cleanup_free_ char *z = strreplace(sd_json_variant_string(variant), "_", "-"); \ + _cleanup_free_ char *z = strdup(sd_json_variant_string(variant)); \ if (!z) \ return json_log_oom(variant, flags); \ \ - cc = func(z); \ + cc = func(json_dashify(z)); \ if (cc < 0) \ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Value of JSON field '%s' not recognized: %s", strna(n), sd_json_variant_string(variant)); \ } \ @@ -261,3 +261,6 @@ enum { int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref); int json_variant_new_devnum(sd_json_variant **ret, dev_t devnum); int json_variant_new_fd_info(sd_json_variant **ret, int fd); + +char *json_underscorify(char *p); +char *json_dashify(char *p); diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index 776df25b8e7..1ef99550b67 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -3474,8 +3474,9 @@ _public_ int sd_json_parse_file( return sd_json_parse_file_at(f, AT_FDCWD, path, flags, ret, reterr_line, reterr_column); } -static char *underscorify(char *p) { - assert(p); +char *json_underscorify(char *p) { + if (!p) + return NULL; /* Replaces "-", "+" by "_", to deal with the usual enum naming rules we have. */ @@ -3485,6 +3486,18 @@ static char *underscorify(char *p) { return p; } +char *json_dashify(char *p) { + if (!p) + return NULL; + + /* Replaces "-", "+" by "-", to (somewhat) undo what json_underscorify() does */ + + for (char *q = p; *q; q++) + *q = IN_SET(*q, '_', '-', '+') ? '-' : *q; + + return p; +} + _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { JsonStack *stack = NULL; size_t n_stack = 1; @@ -3538,7 +3551,7 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { goto finish; } - p = underscorify(c); + p = json_underscorify(c); } r = sd_json_variant_new_string(&add, p); diff --git a/src/shared/varlink-io.systemd.BootControl.c b/src/shared/varlink-io.systemd.BootControl.c index 305fac5c381..11dcb4d0955 100644 --- a/src/shared/varlink-io.systemd.BootControl.c +++ b/src/shared/varlink-io.systemd.BootControl.c @@ -2,7 +2,7 @@ #include "varlink-io.systemd.BootControl.h" -static SD_VARLINK_DEFINE_ENUM_TYPE( +SD_VARLINK_DEFINE_ENUM_TYPE( BootEntryType, SD_VARLINK_FIELD_COMMENT("Boot Loader Specification Type #1 entries (.conf files)"), SD_VARLINK_DEFINE_ENUM_VALUE(type1), @@ -13,7 +13,7 @@ static SD_VARLINK_DEFINE_ENUM_TYPE( SD_VARLINK_FIELD_COMMENT("Automatically generated entries"), SD_VARLINK_DEFINE_ENUM_VALUE(auto)); -static SD_VARLINK_DEFINE_ENUM_TYPE( +SD_VARLINK_DEFINE_ENUM_TYPE( BootEntrySource, SD_VARLINK_FIELD_COMMENT("Boot entry found in EFI system partition (ESP)"), SD_VARLINK_DEFINE_ENUM_VALUE(esp), diff --git a/src/shared/varlink-io.systemd.BootControl.h b/src/shared/varlink-io.systemd.BootControl.h index 2c1fecf4464..1b09f4f0b28 100644 --- a/src/shared/varlink-io.systemd.BootControl.h +++ b/src/shared/varlink-io.systemd.BootControl.h @@ -3,4 +3,7 @@ #include "sd-varlink-idl.h" +extern const sd_varlink_symbol vl_type_BootEntryType; +extern const sd_varlink_symbol vl_type_BootEntrySource; + extern const sd_varlink_interface vl_interface_io_systemd_BootControl; diff --git a/src/shared/varlink-io.systemd.MountFileSystem.c b/src/shared/varlink-io.systemd.MountFileSystem.c index 4d870403383..e9c69f07d82 100644 --- a/src/shared/varlink-io.systemd.MountFileSystem.c +++ b/src/shared/varlink-io.systemd.MountFileSystem.c @@ -3,7 +3,7 @@ #include "bus-polkit.h" #include "varlink-io.systemd.MountFileSystem.h" -static SD_VARLINK_DEFINE_ENUM_TYPE( +SD_VARLINK_DEFINE_ENUM_TYPE( PartitionDesignator, SD_VARLINK_DEFINE_ENUM_VALUE(root), SD_VARLINK_DEFINE_ENUM_VALUE(usr), diff --git a/src/shared/varlink-io.systemd.MountFileSystem.h b/src/shared/varlink-io.systemd.MountFileSystem.h index 0e6ad51e649..6450705892b 100644 --- a/src/shared/varlink-io.systemd.MountFileSystem.h +++ b/src/shared/varlink-io.systemd.MountFileSystem.h @@ -3,4 +3,6 @@ #include "sd-varlink-idl.h" +extern const sd_varlink_symbol vl_type_PartitionDesignator; + extern const sd_varlink_interface vl_interface_io_systemd_MountFileSystem; diff --git a/src/test/test-varlink-idl.c b/src/test/test-varlink-idl.c index 97e3c154c3f..c449d1b3c00 100644 --- a/src/test/test-varlink-idl.c +++ b/src/test/test-varlink-idl.c @@ -7,7 +7,10 @@ #include "sd-varlink.h" #include "sd-varlink-idl.h" +#include "bootspec.h" +#include "dissect-image.h" #include "fd-util.h" +#include "json-util.h" #include "pretty-print.h" #include "tests.h" #include "varlink-idl-util.h" @@ -457,4 +460,58 @@ TEST(validate_method_call) { assert_se(pthread_join(t, NULL) == 0); } +static void test_enum_to_string_name(const char *n, const sd_varlink_symbol *symbol) { + assert(n); + assert(symbol); + + assert(symbol->symbol_type == SD_VARLINK_ENUM_TYPE); + _cleanup_free_ char *m = ASSERT_PTR(json_underscorify(strdup(n))); + + bool found = false; + for (const sd_varlink_field *f = symbol->fields; f->name; f++) { + if (f->field_type == _SD_VARLINK_FIELD_COMMENT) + continue; + + assert(f->field_type == SD_VARLINK_ENUM_VALUE); + if (streq(m, f->name)) { + found = true; + break; + } + } + + log_debug("'%s' found in '%s': %s", m, strna(symbol->name), yes_no(found)); + assert(found); +} + +#define TEST_IDL_ENUM_TO_STRING(type, ename, symbol) \ + for (type t = 0;; t++) { \ + const char *n = ename##_to_string(t); \ + if (!n) \ + break; \ + test_enum_to_string_name(n, &(symbol)); \ + } + +#define TEST_IDL_ENUM_FROM_STRING(type, ename, symbol) \ + for (const sd_varlink_field *f = (symbol).fields; f->name; f++) { \ + if (f->field_type == _SD_VARLINK_FIELD_COMMENT) \ + continue; \ + assert(f->field_type == SD_VARLINK_ENUM_VALUE); \ + _cleanup_free_ char *m = ASSERT_PTR(json_dashify(strdup(f->name))); \ + type t = ename##_from_string(m); \ + log_debug("'%s' of '%s' translates: %s", f->name, strna((symbol).name), yes_no(t >= 0)); \ + assert(t >= 0); \ + } + +#define TEST_IDL_ENUM(type, name, symbol) \ + do { \ + TEST_IDL_ENUM_TO_STRING(type, name, symbol); \ + TEST_IDL_ENUM_FROM_STRING(type, name, symbol); \ + } while (false) + +TEST(enums_idl) { + TEST_IDL_ENUM(BootEntryType, boot_entry_type, vl_type_BootEntryType); + TEST_IDL_ENUM_TO_STRING(BootEntrySource, boot_entry_source, vl_type_BootEntrySource); + TEST_IDL_ENUM(PartitionDesignator, partition_designator, vl_type_PartitionDesignator); +} + DEFINE_TEST_MAIN(LOG_DEBUG);