[libvirt] [PATCH 2/3] json: make it easier to type-check when getting from object

Eric Blake eblake at redhat.com
Sat Jun 20 19:42:09 UTC 2015


While working in qemu_monitor_json, I repeatedly found myself
getting a value then checking if it was an object.  Add some
wrappers to make this task easier.

* src/util/virjson.c (virJSONValueObjectGetByType)
(virJSONValueObjectGetObject, virJSONValueObjectGetArray): New
functions.
(virJSONValueObjectGetString, virJSONValueObjectGetNumberInt)
(virJSONValueObjectGetNumberUint)
(virJSONValueObjectGetNumberLong)
(virJSONValueObjectGetNumberUlong)
(virJSONValueObjectGetNumberDouble)
(virJSONValueObjectGetBoolean): Simplify.
(virJSONValueIsNull): Change return type.
* src/util/virjson.h: Reflect changes.
* src/libvirt_private.syms (virjson.h): Export them.
* tests/jsontest.c (testJSONLookup): New test.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 src/libvirt_private.syms |   3 ++
 src/util/virjson.c       |  76 +++++++++++++++--------------
 src/util/virjson.h       |   8 ++-
 tests/jsontest.c         | 123 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 172 insertions(+), 38 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 51044b0..1566d11 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1632,13 +1632,16 @@ virJSONValueObjectCreate;
 virJSONValueObjectCreateVArgs;
 virJSONValueObjectForeachKeyValue;
 virJSONValueObjectGet;
+virJSONValueObjectGetArray;
 virJSONValueObjectGetBoolean;
+virJSONValueObjectGetByType;
 virJSONValueObjectGetKey;
 virJSONValueObjectGetNumberDouble;
 virJSONValueObjectGetNumberInt;
 virJSONValueObjectGetNumberLong;
 virJSONValueObjectGetNumberUint;
 virJSONValueObjectGetNumberUlong;
+virJSONValueObjectGetObject;
 virJSONValueObjectGetString;
 virJSONValueObjectGetValue;
 virJSONValueObjectHasKey;
diff --git a/src/util/virjson.c b/src/util/virjson.c
index 7d4ece6..29e2c39 100644
--- a/src/util/virjson.c
+++ b/src/util/virjson.c
@@ -766,6 +766,21 @@ virJSONValueObjectGet(virJSONValuePtr object,
 }


+/* Return the value associated with KEY within OBJECT, but return NULL
+ * if the key is missing or if value is not the correct TYPE.  */
+virJSONValuePtr
+virJSONValueObjectGetByType(virJSONValuePtr object,
+                            const char *key,
+                            virJSONType type)
+{
+    virJSONValuePtr value = virJSONValueObjectGet(object, key);
+
+    if (value && value->type == type)
+        return value;
+    return NULL;
+}
+
+
 int
 virJSONValueObjectKeysNumber(virJSONValuePtr object)
 {
@@ -1057,13 +1072,10 @@ virJSONValueNewArrayFromBitmap(virBitmapPtr bitmap)
 }


-int
+bool
 virJSONValueIsNull(virJSONValuePtr val)
 {
-    if (val->type != VIR_JSON_TYPE_NULL)
-        return 0;
-
-    return 1;
+    return val->type == VIR_JSON_TYPE_NULL;
 }


@@ -1071,11 +1083,8 @@ const char *
 virJSONValueObjectGetString(virJSONValuePtr object,
                             const char *key)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return NULL;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return NULL;

@@ -1088,11 +1097,8 @@ virJSONValueObjectGetNumberInt(virJSONValuePtr object,
                                const char *key,
                                int *value)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

@@ -1105,11 +1111,8 @@ virJSONValueObjectGetNumberUint(virJSONValuePtr object,
                                 const char *key,
                                 unsigned int *value)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

@@ -1122,11 +1125,8 @@ virJSONValueObjectGetNumberLong(virJSONValuePtr object,
                                 const char *key,
                                 long long *value)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

@@ -1139,11 +1139,8 @@ virJSONValueObjectGetNumberUlong(virJSONValuePtr object,
                                  const char *key,
                                  unsigned long long *value)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

@@ -1156,11 +1153,8 @@ virJSONValueObjectGetNumberDouble(virJSONValuePtr object,
                                   const char *key,
                                   double *value)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

@@ -1173,11 +1167,8 @@ virJSONValueObjectGetBoolean(virJSONValuePtr object,
                              const char *key,
                              bool *value)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

@@ -1185,15 +1176,26 @@ virJSONValueObjectGetBoolean(virJSONValuePtr object,
 }


+virJSONValuePtr
+virJSONValueObjectGetObject(virJSONValuePtr object, const char *key)
+{
+    return virJSONValueObjectGetByType(object, key, VIR_JSON_TYPE_OBJECT);
+}
+
+
+virJSONValuePtr
+virJSONValueObjectGetArray(virJSONValuePtr object, const char *key)
+{
+    return virJSONValueObjectGetByType(object, key, VIR_JSON_TYPE_ARRAY);
+}
+
+
 int
 virJSONValueObjectIsNull(virJSONValuePtr object,
                          const char *key)
 {
-    virJSONValuePtr val;
-    if (object->type != VIR_JSON_TYPE_OBJECT)
-        return -1;
+    virJSONValuePtr val = virJSONValueObjectGet(object, key);

-    val = virJSONValueObjectGet(object, key);
     if (!val)
         return -1;

diff --git a/src/util/virjson.h b/src/util/virjson.h
index e871b2e..a7df6e5 100644
--- a/src/util/virjson.h
+++ b/src/util/virjson.h
@@ -110,6 +110,8 @@ int virJSONValueArrayAppend(virJSONValuePtr object, virJSONValuePtr value);

 int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key);
 virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key);
+virJSONValuePtr virJSONValueObjectGetByType(virJSONValuePtr object,
+                                            const char *key, virJSONType type);

 bool virJSONValueIsArray(virJSONValuePtr array);
 int virJSONValueArraySize(const virJSONValue *array);
@@ -129,7 +131,11 @@ int virJSONValueGetNumberDouble(virJSONValuePtr object, double *value);
 int virJSONValueGetBoolean(virJSONValuePtr object, bool *value);
 int virJSONValueGetArrayAsBitmap(const virJSONValue *val, virBitmapPtr *bitmap)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int virJSONValueIsNull(virJSONValuePtr object);
+bool virJSONValueIsNull(virJSONValuePtr object);
+virJSONValuePtr virJSONValueObjectGetObject(virJSONValuePtr object,
+                                            const char *key);
+virJSONValuePtr virJSONValueObjectGetArray(virJSONValuePtr object,
+                                           const char *key);

 const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key);
 int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value);
diff --git a/tests/jsontest.c b/tests/jsontest.c
index f226c92..34a07ee 100644
--- a/tests/jsontest.c
+++ b/tests/jsontest.c
@@ -119,6 +119,114 @@ testJSONAddRemove(const void *data)


 static int
+testJSONLookup(const void *data)
+{
+    const struct testInfo *info = data;
+    virJSONValuePtr json;
+    virJSONValuePtr value = NULL;
+    char *result = NULL;
+    int rc;
+    int number;
+    const char *str;
+    int ret = -1;
+
+    json = virJSONValueFromString(info->doc);
+    if (!json) {
+        VIR_TEST_VERBOSE("Fail to parse %s\n", info->doc);
+        ret = -1;
+        goto cleanup;
+    }
+
+    value = virJSONValueObjectGetObject(json, "a");
+    if (value) {
+        if (!info->pass) {
+            VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have failed\n",
+                             info->doc);
+            goto cleanup;
+        } else {
+            result = virJSONValueToString(value, false);
+            if (STRNEQ_NULLABLE(result, "{}")) {
+                VIR_TEST_VERBOSE("lookup for 'a' in '%s' found '%s' but "
+                                 "should have found '{}'\n",
+                                 info->doc, NULLSTR(result));
+                goto cleanup;
+            }
+            VIR_FREE(result);
+        }
+    } else if (info->pass) {
+        VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have succeeded\n",
+                         info->doc);
+        goto cleanup;
+    }
+
+    number = 2;
+    rc = virJSONValueObjectGetNumberInt(json, "b", &number);
+    if (rc == 0) {
+        if (!info->pass) {
+            VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have failed\n",
+                             info->doc);
+            goto cleanup;
+        } else if (number != 1) {
+            VIR_TEST_VERBOSE("lookup for 'b' in '%s' found %d but "
+                             "should have found 1\n",
+                             info->doc, number);
+            goto cleanup;
+        }
+    } else if (info->pass) {
+        VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have succeeded\n",
+                         info->doc);
+        goto cleanup;
+    }
+
+    str = virJSONValueObjectGetString(json, "c");
+    if (str) {
+        if (!info->pass) {
+            VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have failed\n",
+                             info->doc);
+            goto cleanup;
+        } else if (STRNEQ(str, "str")) {
+            VIR_TEST_VERBOSE("lookup for 'c' in '%s' found '%s' but "
+                             "should have found 'str'\n", info->doc, str);
+                goto cleanup;
+        }
+    } else if (info->pass) {
+        VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have succeeded\n",
+                         info->doc);
+        goto cleanup;
+    }
+
+    value = virJSONValueObjectGetArray(json, "d");
+    if (value) {
+        if (!info->pass) {
+            VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have failed\n",
+                             info->doc);
+            goto cleanup;
+        } else {
+            result = virJSONValueToString(value, false);
+            if (STRNEQ_NULLABLE(result, "[]")) {
+                VIR_TEST_VERBOSE("lookup for 'd' in '%s' found '%s' but "
+                                 "should have found '[]'\n",
+                                 info->doc, NULLSTR(result));
+                goto cleanup;
+            }
+            VIR_FREE(result);
+        }
+    } else if (info->pass) {
+        VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have succeeded\n",
+                         info->doc);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virJSONValueFree(json);
+    VIR_FREE(result);
+    return ret;
+}
+
+
+static int
 testJSONCopy(const void *data)
 {
     const struct testInfo *info = data;
@@ -319,6 +427,21 @@ mymain(void)
                        "[ {[\"key1\", \"key2\"]: \"value\"} ]");
     DO_TEST_PARSE_FAIL("object with unterminated key", "{ \"key:7 }");

+    DO_TEST_FULL("lookup on array", Lookup,
+                 "[ 1 ]", NULL, false);
+    DO_TEST_FULL("lookup on string", Lookup,
+                 "\"str\"", NULL, false);
+    DO_TEST_FULL("lookup on integer", Lookup,
+                 "1", NULL, false);
+    DO_TEST_FULL("lookup with missing key", Lookup,
+                 "{ }", NULL, false);
+    DO_TEST_FULL("lookup with wrong type", Lookup,
+                 "{ \"a\": 1, \"b\": \"str\", \"c\": [], \"d\": {} }",
+                 NULL, false);
+    DO_TEST_FULL("lookup with correct type", Lookup,
+                 "{ \"a\": {}, \"b\": 1, \"c\": \"str\", \"d\": [] }",
+                 NULL, true);
+
     return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }

-- 
2.4.3




More information about the libvir-list mailing list