diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h index fdfd5522db0..3823eb32ddb 100644 --- a/src/libsystemd/sd-json/json-util.h +++ b/src/libsystemd/sd-json/json-util.h @@ -138,20 +138,35 @@ enum { _JSON_BUILD_IOVEC_HEX, _JSON_BUILD_HW_ADDR, _JSON_BUILD_STRING_SET, + _JSON_BUILD_STRING_ORDERED_SET, _JSON_BUILD_STRING_UNDERSCORIFY, _JSON_BUILD_DUAL_TIMESTAMP, + _JSON_BUILD_RATELIMIT, + _JSON_BUILD_TRISTATE, + _JSON_BUILD_PAIR_INTEGER_NON_ZERO, + _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE, _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, + _JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL, _JSON_BUILD_PAIR_FINITE_USEC, _JSON_BUILD_PAIR_STRING_NON_EMPTY, _JSON_BUILD_PAIR_STRV_NON_EMPTY, _JSON_BUILD_PAIR_VARIANT_NON_NULL, /* _SD_JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, */ + _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, + _JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL, + _JSON_BUILD_PAIR_RATELIMIT_ENABLED, + _JSON_BUILD_PAIR_CALLBACK_NON_NULL, + _JSON_BUILD_PAIR_BASE64_NON_EMPTY, + _JSON_BUILD_PAIR_BASE32HEX_NON_EMPTY, + _JSON_BUILD_PAIR_HEX_NON_EMPTY, + _JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY, + _JSON_BUILD_PAIR_TRISTATE_NON_NULL, _SD_JSON_BUILD_REALLYMAX, }; @@ -166,19 +181,34 @@ enum { #define JSON_BUILD_ETHER_ADDR(v) SD_JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr)) #define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v } #define JSON_BUILD_STRING_SET(s) _JSON_BUILD_STRING_SET, (Set *) { s } +#define JSON_BUILD_STRING_ORDERED_SET(s) _JSON_BUILD_STRING_ORDERED_SET, (OrderedSet *) { s } #define JSON_BUILD_STRING_UNDERSCORIFY(s) _JSON_BUILD_STRING_UNDERSCORIFY, (const char *) { s } #define JSON_BUILD_DUAL_TIMESTAMP(t) _JSON_BUILD_DUAL_TIMESTAMP, (dual_timestamp*) { t } +#define JSON_BUILD_RATELIMIT(rl) _JSON_BUILD_RATELIMIT, (const RateLimit*) { rl } +#define JSON_BUILD_TRISTATE(i) _JSON_BUILD_TRISTATE, (int) { i } +#define JSON_BUILD_PAIR_INTEGER_NON_ZERO(name, i) _JSON_BUILD_PAIR_INTEGER_NON_ZERO, (const char*) { name }, (int64_t) { i } +#define JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE(name, i) _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE, (const char*) { name }, (int64_t) { i } #define JSON_BUILD_PAIR_UNSIGNED_NON_ZERO(name, u) _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, (const char*) { name }, (uint64_t) { u } +#define JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL(name, u, eq) _JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL, (const char*) { name }, (uint64_t) { u }, (uint64_t) { eq } #define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u } #define JSON_BUILD_PAIR_STRING_NON_EMPTY(name, s) _JSON_BUILD_PAIR_STRING_NON_EMPTY, (const char*) { name }, (const char*) { s } #define JSON_BUILD_PAIR_STRV_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_NON_EMPTY, (const char*) { name }, (char**) { l } #define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (sd_json_variant*) { v } +#define JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } #define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v } #define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v } #define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, v, f) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (const union in_addr_union*) { v }, (int) { f } #define JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, (const char*) { name }, (const struct ether_addr*) { v } #define JSON_BUILD_PAIR_HW_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, (const char*) { name }, (const struct hw_addr_data*) { v } +#define JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL(name, t) _JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL, (const char*) { name }, (dual_timestamp*) { t } +#define JSON_BUILD_PAIR_RATELIMIT_ENABLED(name, rl) _JSON_BUILD_PAIR_RATELIMIT_ENABLED, (const char*) { name }, (const RateLimit*) { rl } +#define JSON_BUILD_PAIR_CALLBACK_NON_NULL(name, c, u) _JSON_BUILD_PAIR_CALLBACK_NON_NULL, (const char*) { name }, (sd_json_build_callback_t) { c }, (void*) { u } +#define JSON_BUILD_PAIR_BASE64_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BASE64_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } +#define JSON_BUILD_PAIR_BASE32HEX_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_BASE32HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } +#define JSON_BUILD_PAIR_HEX_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } +#define JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY(name, v, n) _JSON_BUILD_PAIR_HEX_NON_EMPTY, (const char*) { name }, (const void*) { v }, (size_t) { n } +#define JSON_BUILD_PAIR_TRISTATE_NON_NULL(name, i) _JSON_BUILD_PAIR_TRISTATE_NON_NULL, (const char*) { name }, (int) { i } #define JSON_BUILD_PAIR_IOVEC_BASE64(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_BASE64(iov)) #define JSON_BUILD_PAIR_IOVEC_HEX(name, iov) SD_JSON_BUILD_PAIR(name, JSON_BUILD_IOVEC_HEX(iov)) @@ -188,3 +218,7 @@ enum { #define JSON_BUILD_PAIR_ETHER_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v)) #define JSON_BUILD_PAIR_HW_ADDR(name, v) SD_JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v)) #define JSON_BUILD_PAIR_STRING_SET(name, s) SD_JSON_BUILD_PAIR(name, JSON_BUILD_STRING_SET(s)) +#define JSON_BUILD_PAIR_STRING_ORDERED_SET(name, s) SD_JSON_BUILD_PAIR(name, JSON_BUILD_STRING_ORDERED_SET(s)) +#define JSON_BUILD_PAIR_DUAL_TIMESTAMP(name, t) SD_JSON_BUILD_PAIR(name, JSON_BUILD_DUAL_TIMESTAMP(t)) +#define JSON_BUILD_PAIR_RATELIMIT(name, rl) SD_JSON_BUILD_PAIR(name, JSON_BUILD_RATELIMIT(rl)) +#define JSON_BUILD_PAIR_TRISTATE(name, i) SD_JSON_BUILD_PAIR(name, JSON_BUILD_TRISTATE(i)) diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index 589bbe3a46e..20599114ab5 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -23,6 +23,7 @@ #include "iovec-util.h" #include "json-internal.h" #include "json-util.h" +#include "ordered-set.h" #include "macro.h" #include "math-util.h" #include "memory-util.h" @@ -4089,6 +4090,42 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { break; } + case _JSON_BUILD_STRING_ORDERED_SET: { + OrderedSet *set; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + set = va_arg(ap, OrderedSet*); + + if (current->n_suppress == 0) { + _cleanup_free_ char **sv = NULL; + + sv = ordered_set_get_strv(set); + if (!sv) { + r = -ENOMEM; + goto finish; + } + + r = sd_json_variant_new_array_strv(&add, sv); + if (r < 0) + goto finish; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _JSON_BUILD_DUAL_TIMESTAMP: { dual_timestamp *ts; @@ -4123,6 +4160,71 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { break; } + case _JSON_BUILD_RATELIMIT: { + const RateLimit *rl; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + rl = va_arg(ap, const RateLimit*); + + if (current->n_suppress == 0) { + if (ratelimit_configured(rl)) { + r = sd_json_buildo( + &add, + SD_JSON_BUILD_PAIR("intervalUSec", SD_JSON_BUILD_UNSIGNED(rl->interval)), + SD_JSON_BUILD_PAIR("burst", SD_JSON_BUILD_UNSIGNED(rl->burst))); + if (r < 0) + goto finish; + } else + add = JSON_VARIANT_MAGIC_NULL; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + + case _JSON_BUILD_TRISTATE: { + int tristate; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + tristate = va_arg(ap, int); + + if (current->n_suppress == 0) { + if (tristate >= 0) { + r = sd_json_variant_new_boolean(&add, tristate); + if (r < 0) + goto finish; + } else + add = JSON_VARIANT_MAGIC_NULL; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _SD_JSON_BUILD_CALLBACK: { sd_json_build_callback_t cb; void *userdata; @@ -4259,9 +4361,47 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { break; } - case _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO: { + case _JSON_BUILD_PAIR_INTEGER_NON_ZERO: + case _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE: { const char *n; - uint64_t u; + int64_t i; + bool include; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char*); + i = va_arg(ap, int64_t); + + if (command == _JSON_BUILD_PAIR_INTEGER_NON_ZERO) + include = i != 0; + else if (command == _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE) + include = i >= 0; + else + assert_not_reached(); + + if (include && current->n_suppress == 0) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = sd_json_variant_new_integer(&add_more, i); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO: + case _JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL: { + const char *n; + uint64_t u, eq; if (current->expect != EXPECT_OBJECT_KEY) { r = -EINVAL; @@ -4270,8 +4410,9 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { n = va_arg(ap, const char *); u = va_arg(ap, uint64_t); + eq = command == _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO ? 0 : va_arg(ap, uint64_t); - if (u != 0 && current->n_suppress == 0) { + if (u != eq && current->n_suppress == 0) { r = sd_json_variant_new_string(&add, n); if (r < 0) goto finish; @@ -4396,6 +4537,36 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { break; } + case _JSON_BUILD_PAIR_BYTE_ARRAY_NON_EMPTY: { + const void *array; + size_t sz; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + array = va_arg(ap, const void*); + sz = va_arg(ap, size_t); + + if (sz > 0 && current->n_suppress == 0) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = sd_json_variant_new_array_bytes(&add_more, array, sz); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + case _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL: { const struct in_addr *a; const char *n; @@ -4537,6 +4708,164 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) { current->expect = EXPECT_OBJECT_KEY; break; } + + case _JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL: { + const dual_timestamp *ts; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char*); + ts = va_arg(ap, const dual_timestamp*); + + if (ts && dual_timestamp_is_set(ts) && current->n_suppress == 0) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = sd_json_buildo(&add_more, + SD_JSON_BUILD_PAIR("realtime", SD_JSON_BUILD_UNSIGNED(ts->realtime)), + SD_JSON_BUILD_PAIR("monotonic", SD_JSON_BUILD_UNSIGNED(ts->monotonic))); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_RATELIMIT_ENABLED: { + const RateLimit *rl; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char*); + rl = va_arg(ap, const RateLimit*); + + if (rl && ratelimit_configured(rl) && current->n_suppress == 0) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = sd_json_buildo(&add_more, + SD_JSON_BUILD_PAIR("intervalUSec", SD_JSON_BUILD_UNSIGNED(rl->interval)), + SD_JSON_BUILD_PAIR("burst", SD_JSON_BUILD_UNSIGNED(rl->burst))); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_CALLBACK_NON_NULL: { + sd_json_build_callback_t cb; + void *userdata; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char*); + cb = va_arg(ap, sd_json_build_callback_t); + userdata = va_arg(ap, void*); + + if (current->n_suppress == 0) { + if (cb) { + r = cb(&add_more, n, userdata); + if (r < 0) + goto finish; + } + + if (add_more) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + } + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_BASE64_NON_EMPTY: + case _JSON_BUILD_PAIR_BASE32HEX_NON_EMPTY: + case _JSON_BUILD_PAIR_HEX_NON_EMPTY: + case _JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY: { + const void *p; + size_t sz; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char*); + p = va_arg(ap, const void *); + sz = va_arg(ap, size_t); + + if (sz > 0 && current->n_suppress == 0) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = command == _SD_JSON_BUILD_BASE64 ? sd_json_variant_new_base64(&add_more, p, sz) : + command == _SD_JSON_BUILD_BASE32HEX ? sd_json_variant_new_base32hex(&add_more, p, sz) : + command == _SD_JSON_BUILD_HEX ? sd_json_variant_new_hex(&add_more, p, sz) : + sd_json_variant_new_octescape(&add_more, p, sz); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_TRISTATE_NON_NULL: { + int tristate; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char*); + tristate = va_arg(ap, int); + + if (tristate >= 0 && current->n_suppress == 0) { + r = sd_json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = sd_json_variant_new_boolean(&add_more, tristate); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } } /* If variants were generated, add them to our current variant, but only if we are not supposed to suppress additions */ diff --git a/src/test/test-json.c b/src/test/test-json.c index aea4bbaf3ef..378a3d0d8de 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -12,6 +12,7 @@ #include "json-internal.h" #include "json-util.h" #include "math-util.h" +#include "ordered-set.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -280,6 +281,8 @@ static int test_callback(sd_json_variant **ret, const char *name, void *userdata assert_se(PTR_TO_INT(userdata) == 4711); else if (streq_ptr(name, "mypid2")) assert_se(PTR_TO_INT(userdata) == 4712); + else if (streq_ptr(name, "mypid3")) + return 0; else assert_not_reached(); @@ -401,6 +404,16 @@ TEST(build) { assert_se(sd_json_variant_format(y, /* flags= */ 0, &f2)); ASSERT_STREQ(f1, f2); + _cleanup_(sd_json_variant_unrefp) sd_json_variant *z = NULL; + ASSERT_OK(sd_json_build(&z, SD_JSON_BUILD_OBJECT(JSON_BUILD_PAIR_CALLBACK_NON_NULL("mypid3", test_callback, INT_TO_PTR(4713))))); + ASSERT_TRUE(sd_json_variant_is_blank_object(z)); + z = sd_json_variant_unref(z); + f2 = mfree(f2); + ASSERT_OK(sd_json_build(&z, SD_JSON_BUILD_OBJECT(JSON_BUILD_PAIR_CALLBACK_NON_NULL("mypid1", test_callback, INT_TO_PTR(4711)), + JSON_BUILD_PAIR_CALLBACK_NON_NULL("mypid2", test_callback, INT_TO_PTR(4712))))); + ASSERT_OK(sd_json_variant_format(z, /* flags= */ 0, &f2)); + ASSERT_STREQ(f1, f2); + _cleanup_set_free_ Set *ss = NULL; assert_se(set_ensure_put(&ss, &string_hash_ops_free, ASSERT_PTR(strdup("pief"))) >= 0); assert_se(set_ensure_put(&ss, &string_hash_ops_free, ASSERT_PTR(strdup("xxxx"))) >= 0); @@ -414,6 +427,19 @@ TEST(build) { assert_se(sd_json_build(&ssv2, SD_JSON_BUILD_LITERAL("{\"zzz\":[\"kawumm\",\"pief\",\"xxxx\"]}")) >= 0); assert_se(sd_json_variant_equal(ssv, ssv2)); + + _cleanup_ordered_set_free_ OrderedSet *oss = NULL; + assert_se(ordered_set_ensure_put(&oss, &string_hash_ops_free, ASSERT_PTR(strdup("pief"))) >= 0); + assert_se(ordered_set_ensure_put(&oss, &string_hash_ops_free, ASSERT_PTR(strdup("xxxx"))) >= 0); + assert_se(ordered_set_ensure_put(&oss, &string_hash_ops_free, ASSERT_PTR(strdup("kawumm"))) >= 0); + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *ossv = NULL; + assert_se(sd_json_build(&ossv, SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("zzz", JSON_BUILD_STRING_ORDERED_SET(oss)))) >= 0); + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *ossv2 = NULL; + assert_se(sd_json_build(&ossv2, SD_JSON_BUILD_LITERAL("{\"zzz\":[\"pief\",\"xxxx\",\"kawumm\"]}")) >= 0); + + assert_se(sd_json_variant_equal(ossv, ossv2)); } TEST(json_buildo) {