mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
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:
parent
ceb496e5f0
commit
58fd670335
@ -1632,13 +1632,16 @@ virJSONValueObjectCreate;
|
||||
virJSONValueObjectCreateVArgs;
|
||||
virJSONValueObjectForeachKeyValue;
|
||||
virJSONValueObjectGet;
|
||||
virJSONValueObjectGetArray;
|
||||
virJSONValueObjectGetBoolean;
|
||||
virJSONValueObjectGetByType;
|
||||
virJSONValueObjectGetKey;
|
||||
virJSONValueObjectGetNumberDouble;
|
||||
virJSONValueObjectGetNumberInt;
|
||||
virJSONValueObjectGetNumberLong;
|
||||
virJSONValueObjectGetNumberUint;
|
||||
virJSONValueObjectGetNumberUlong;
|
||||
virJSONValueObjectGetObject;
|
||||
virJSONValueObjectGetString;
|
||||
virJSONValueObjectGetValue;
|
||||
virJSONValueObjectHasKey;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
123
tests/jsontest.c
123
tests/jsontest.c
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user