]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/json: make it possible to specify source name for strings too, add tests
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 17 Nov 2022 13:15:48 +0000 (14:15 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 1 Dec 2022 17:02:06 +0000 (18:02 +0100)
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.

src/shared/json.c
src/shared/json.h
src/test/test-json.c

index 94d7b3155705cf29e22b5f7921b879a14697b1e8..98bae0f194452a662789223d44dd002cfd1fb786 100644 (file)
@@ -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) {
index c5f052a9d569bbcafc83c3afca3a61c619611ae7..b1658b5f4bd1ab7f95af71c424f58837f6b57ad7 100644 (file)
@@ -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) {
index 17ad2017f8c966aab547440c6579876e68408280..7ff9c560dd34c802011b9a516df4f9004041dc2d 100644 (file)
@@ -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);