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(a)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