From: Zbigniew Jędrzejewski-Szmek Date: Thu, 17 Nov 2022 13:15:48 +0000 (+0100) Subject: shared/json: make it possible to specify source name for strings too, add tests X-Git-Tag: v253-rc1~334^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b0eeb945881b86f6740b84c055f0ad2be7a09ad1;p=thirdparty%2Fsystemd.git shared/json: make it possible to specify source name for strings too, add tests The source would be set implicitly when parsing from a named file. But it's useful to specify the source also for cases where we're parsing a ready string. I noticed the lack of this API when trying to write tests, but it seems generally useful to be specify a source name when parsing things. --- diff --git a/src/shared/json.c b/src/shared/json.c index 94d7b315570..98bae0f1944 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -3180,16 +3180,53 @@ finish: return r; } -int json_parse(const char *input, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) { - return json_parse_internal(&input, NULL, flags, ret, ret_line, ret_column, false); +int json_parse_with_source( + const char *input, + const char *source, + JsonParseFlags flags, + JsonVariant **ret, + unsigned *ret_line, + unsigned *ret_column) { + + _cleanup_(json_source_unrefp) JsonSource *s = NULL; + + if (source) { + s = json_source_new(source); + if (!s) + return -ENOMEM; + } + + return json_parse_internal(&input, s, flags, ret, ret_line, ret_column, false); } -int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) { - return json_parse_internal(p, NULL, flags, ret, ret_line, ret_column, true); +int json_parse_with_source_continue( + const char **p, + const char *source, + JsonParseFlags flags, + JsonVariant **ret, + unsigned *ret_line, + unsigned *ret_column) { + + _cleanup_(json_source_unrefp) JsonSource *s = NULL; + + if (source) { + s = json_source_new(source); + if (!s) + return -ENOMEM; + } + + return json_parse_internal(p, s, flags, ret, ret_line, ret_column, true); } -int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) { - _cleanup_(json_source_unrefp) JsonSource *source = NULL; +int json_parse_file_at( + FILE *f, + int dir_fd, + const char *path, + JsonParseFlags flags, + JsonVariant **ret, + unsigned *ret_line, + unsigned *ret_column) { + _cleanup_free_ char *text = NULL; int r; @@ -3205,14 +3242,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla if (isempty(text)) return -ENODATA; - if (path) { - source = json_source_new(path); - if (!source) - return -ENOMEM; - } - - const char *p = text; - return json_parse_internal(&p, source, flags, ret, ret_line, ret_column, false); + return json_parse_with_source(text, path, flags, ret, ret_line, ret_column); } int json_buildv(JsonVariant **ret, va_list ap) { diff --git a/src/shared/json.h b/src/shared/json.h index c5f052a9d56..b1658b5f4bd 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -222,8 +222,16 @@ typedef enum JsonParseFlags { JSON_PARSE_SENSITIVE = 1 << 0, /* mark variant as "sensitive", i.e. something containing secret key material or such */ } JsonParseFlags; -int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); -int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); +int json_parse_with_source(const char *string, const char *source, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); +int json_parse_with_source_continue(const char **p, const char *source, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); + +static inline int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) { + return json_parse_with_source(string, NULL, flags, ret, ret_line, ret_column); +} +static inline int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) { + return json_parse_with_source_continue(p, NULL, flags, ret, ret_line, ret_column); +} + int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); static inline int json_parse_file(FILE *f, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) { diff --git a/src/test/test-json.c b/src/test/test-json.c index 17ad2017f8c..7ff9c560dd3 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -663,4 +663,67 @@ TEST(json_append) { assert_se(json_variant_equal(v, w)); } +static inline void json_array_append_with_source_one(bool source) { + _cleanup_(json_variant_unrefp) JsonVariant *a, *b; + + /* Parse two sources, each with a different name and line/column numbers */ + + assert_se(json_parse_with_source(" [41]", source ? "string 1" : NULL, 0, + &a, NULL, NULL) >= 0); + assert_se(json_parse_with_source("\n\n [42]", source ? "string 2" : NULL, 0, + &b, NULL, NULL) >= 0); + + assert_se(json_variant_is_array(a)); + assert_se(json_variant_elements(a) == 1); + assert_se(json_variant_is_array(b)); + assert_se(json_variant_elements(b) == 1); + + /* Verify source information */ + + const char *s1, *s2; + unsigned line1, col1, line2, col2; + assert_se(json_variant_get_source(a, &s1, &line1, &col1) >= 0); + assert_se(json_variant_get_source(b, &s2, &line2, &col2) >= 0); + + assert_se(streq_ptr(s1, source ? "string 1" : NULL)); + assert_se(streq_ptr(s2, source ? "string 2" : NULL)); + assert_se(line1 == 1); + assert_se(col1 == 2); + assert_se(line2 == 3); + assert_se(col2 == 4); + + /* Append one elem from the second array (and source) to the first. */ + + JsonVariant *elem; + assert_se(elem = json_variant_by_index(b, 0)); + assert_se(json_variant_is_integer(elem)); + assert_se(json_variant_elements(elem) == 0); + + assert_se(json_variant_append_array(&a, elem) >= 0); + + assert_se(json_variant_is_array(a)); + assert_se(json_variant_elements(a) == 2); + + /* Verify that source information was propagated correctly */ + + assert_se(json_variant_get_source(elem, &s1, &line1, &col1) >= 0); + assert_se(elem = json_variant_by_index(a, 1)); + assert_se(json_variant_get_source(elem, &s2, &line2, &col2) >= 0); + + assert_se(streq_ptr(s1, source ? "string 2" : NULL)); + assert_se(streq_ptr(s2, source ? "string 2" : NULL)); + assert_se(line1 == 3); + assert_se(col1 == 5); + assert_se(line2 == 3); + assert_se(col2 == 5); +} + +TEST(json_array_append_with_source) { + json_array_append_with_source_one(true); +} + +TEST(json_array_append_without_source) { + json_array_append_with_source_one(false); +} + DEFINE_TEST_MAIN(LOG_DEBUG);