]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlink-idl: add infra to test our enum parsers against varlink IDL enums
authorLennart Poettering <lennart@poettering.net>
Tue, 4 Nov 2025 09:35:00 +0000 (10:35 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 4 Nov 2025 11:46:17 +0000 (11:46 +0000)
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).

src/libsystemd/sd-json/json-util.h
src/libsystemd/sd-json/sd-json.c
src/shared/varlink-io.systemd.BootControl.c
src/shared/varlink-io.systemd.BootControl.h
src/shared/varlink-io.systemd.MountFileSystem.c
src/shared/varlink-io.systemd.MountFileSystem.h
src/test/test-varlink-idl.c

index c2d353476d2b31e95e3822d8ef4fb8d0df87dc7c..f4b9b4e7e11eb38affc2c8094eda8859a1ec4b41 100644 (file)
@@ -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);
index 776df25b8e783acfc213fe5e69f574e5a38823b1..1ef99550b6708a81c4f36883a12eb6e903d62491 100644 (file)
@@ -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);
index 305fac5c381d7fe3e0f7ee0ca38024c0eb69bc06..11dcb4d09552c20c02c2fec7efdf2830f500fa42 100644 (file)
@@ -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),
index 2c1fecf4464399fc0214109ef2806c1c19a1a934..1b09f4f0b284c7e6b07375aa896736afa9510810 100644 (file)
@@ -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;
index 4d8704033833725258b0f4602ed10c2546e58079..e9c69f07d825817d3a1e837e3d08ef7843db1cba 100644 (file)
@@ -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),
index 0e6ad51e649b18fdf5f310b3a282290b9175f13f..6450705892b61ff7afd767b48aa4c688a47d11be 100644 (file)
@@ -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;
index 97e3c154c3f32a90925e0a724bd03de60e303064..c449d1b3c00c8194a1f49cc602b996bb29799fd4 100644 (file)
@@ -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);