json: make it easier to type-check when getting from object

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@redhat.com>
This commit is contained in:
Eric Blake 2015-06-19 17:13:03 -06:00
parent ceb496e5f0
commit 58fd670335
4 changed files with 172 additions and 38 deletions

View File

@ -1632,13 +1632,16 @@ virJSONValueObjectCreate;
virJSONValueObjectCreateVArgs;
virJSONValueObjectForeachKeyValue;
virJSONValueObjectGet;
virJSONValueObjectGetArray;
virJSONValueObjectGetBoolean;
virJSONValueObjectGetByType;
virJSONValueObjectGetKey;
virJSONValueObjectGetNumberDouble;
virJSONValueObjectGetNumberInt;
virJSONValueObjectGetNumberLong;
virJSONValueObjectGetNumberUint;
virJSONValueObjectGetNumberUlong;
virJSONValueObjectGetObject;
virJSONValueObjectGetString;
virJSONValueObjectGetValue;
virJSONValueObjectHasKey;

View File

@ -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;

View File

@ -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);

View File

@ -118,6 +118,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)
{
@ -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;
}