From: Lennart Poettering Date: Sun, 17 May 2026 06:46:59 +0000 (+0200) Subject: test: add unit test for new sd-json functionality X-Git-Tag: v261-rc1~120^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F42136%2Fhead;p=thirdparty%2Fsystemd.git test: add unit test for new sd-json functionality --- diff --git a/src/libsystemd/sd-json/test-json.c b/src/libsystemd/sd-json/test-json.c index 3be4b09660b..c9aa5d2f901 100644 --- a/src/libsystemd/sd-json/test-json.c +++ b/src/libsystemd/sd-json/test-json.c @@ -13,6 +13,7 @@ #include "fd-util.h" #include "format-util.h" #include "fileio.h" +#include "io-util.h" #include "iovec-util.h" #include "json-internal.h" #include "json-util.h" @@ -518,6 +519,68 @@ TEST(source) { printf("--- pretty end ---\n"); } +TEST(parse_fd) { + static const char data[] = "{ \"foo\" : \"bar\", \"baz\" : 4711 }"; + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + _cleanup_close_ int fd = -EBADF; + + ASSERT_OK(fd = open_tmpfile_unlinkable(NULL, O_RDWR)); + ASSERT_OK(loop_write(fd, data, strlen(data))); + + /* By default the fd is internally duplicated, the caller's fd stays open and the JSON text is + * read starting at the current file offset. */ + ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_SET)); + ASSERT_OK(sd_json_parse_fd("tmpfile", fd, /* flags= */ 0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL)); + ASSERT_OK(fd_validate(fd)); /* still open, we only got a duplicate */ + ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar"); + ASSERT_EQ(sd_json_variant_unsigned(sd_json_variant_by_key(v, "baz")), UINT64_C(4711)); + v = sd_json_variant_unref(v); + + /* Without SD_JSON_PARSE_SEEK0 and with the offset left at EOF there is nothing to read. */ + ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_END)); + ASSERT_ERROR(sd_json_parse_fd("tmpfile", fd, /* flags= */ 0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL), ENODATA); + ASSERT_NULL(v); + ASSERT_OK(fd_validate(fd)); + + /* SD_JSON_PARSE_SEEK0 rewinds to the beginning first, so the stale offset no longer matters. */ + ASSERT_OK(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_SEEK0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL)); + ASSERT_OK(fd_validate(fd)); + ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar"); + v = sd_json_variant_unref(v); + + /* SD_JSON_PARSE_REOPEN_FD reopens the fd internally (starting at offset 0), the caller's fd and + * its offset are left untouched. */ + ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_END)); + ASSERT_OK(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_REOPEN_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL)); + ASSERT_OK(fd_validate(fd)); + ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar"); + v = sd_json_variant_unref(v); + + /* SD_JSON_PARSE_REOPEN_FD and SD_JSON_PARSE_DONATE_FD are mutually exclusive. */ + ASSERT_RETURN_EXPECTED_SE(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_REOPEN_FD|SD_JSON_PARSE_DONATE_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL) == -EINVAL); + ASSERT_OK(fd_validate(fd)); /* not consumed on the -EINVAL path */ + + /* SD_JSON_PARSE_DONATE_FD passes ownership into the call: the fd is consumed and closed even on + * success. */ + ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_SET)); + ASSERT_OK(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_DONATE_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL)); + ASSERT_ERROR(fd_validate(fd), EBADF); + TAKE_FD(fd); /* already closed by the call, don't double-close */ + ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar"); + v = sd_json_variant_unref(v); + + /* SD_JSON_PARSE_DONATE_FD also consumes the fd when parsing fails. */ + _cleanup_close_ int fd2 = -EBADF; + ASSERT_OK(fd2 = open_tmpfile_unlinkable(NULL, O_RDWR)); + ASSERT_OK(loop_write(fd2, "kookoo", strlen("kookoo"))); + ASSERT_OK_ERRNO(lseek(fd2, 0, SEEK_SET)); + ASSERT_ERROR(sd_json_parse_fd("tmpfile", fd2, SD_JSON_PARSE_DONATE_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL), EINVAL); + ASSERT_ERROR(fd_validate(fd2), EBADF); + TAKE_FD(fd2); + ASSERT_NULL(v); +} + TEST(depth) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; int r;