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).
This commit is contained in:
Lennart Poettering
2025-11-04 10:35:00 +01:00
committed by Luca Boccassi
parent 79dd24cf14
commit 030f239a19
7 changed files with 86 additions and 8 deletions

View 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);

View 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);

View 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),

View 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;

View 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),

View 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;

View 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);