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;
|
virJSONValueObjectCreateVArgs;
|
||||||
virJSONValueObjectForeachKeyValue;
|
virJSONValueObjectForeachKeyValue;
|
||||||
virJSONValueObjectGet;
|
virJSONValueObjectGet;
|
||||||
|
virJSONValueObjectGetArray;
|
||||||
virJSONValueObjectGetBoolean;
|
virJSONValueObjectGetBoolean;
|
||||||
|
virJSONValueObjectGetByType;
|
||||||
virJSONValueObjectGetKey;
|
virJSONValueObjectGetKey;
|
||||||
virJSONValueObjectGetNumberDouble;
|
virJSONValueObjectGetNumberDouble;
|
||||||
virJSONValueObjectGetNumberInt;
|
virJSONValueObjectGetNumberInt;
|
||||||
virJSONValueObjectGetNumberLong;
|
virJSONValueObjectGetNumberLong;
|
||||||
virJSONValueObjectGetNumberUint;
|
virJSONValueObjectGetNumberUint;
|
||||||
virJSONValueObjectGetNumberUlong;
|
virJSONValueObjectGetNumberUlong;
|
||||||
|
virJSONValueObjectGetObject;
|
||||||
virJSONValueObjectGetString;
|
virJSONValueObjectGetString;
|
||||||
virJSONValueObjectGetValue;
|
virJSONValueObjectGetValue;
|
||||||
virJSONValueObjectHasKey;
|
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
|
int
|
||||||
virJSONValueObjectKeysNumber(virJSONValuePtr object)
|
virJSONValueObjectKeysNumber(virJSONValuePtr object)
|
||||||
{
|
{
|
||||||
@ -1057,13 +1072,10 @@ virJSONValueNewArrayFromBitmap(virBitmapPtr bitmap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
bool
|
||||||
virJSONValueIsNull(virJSONValuePtr val)
|
virJSONValueIsNull(virJSONValuePtr val)
|
||||||
{
|
{
|
||||||
if (val->type != VIR_JSON_TYPE_NULL)
|
return val->type == VIR_JSON_TYPE_NULL;
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1071,11 +1083,8 @@ const char *
|
|||||||
virJSONValueObjectGetString(virJSONValuePtr object,
|
virJSONValueObjectGetString(virJSONValuePtr object,
|
||||||
const char *key)
|
const char *key)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -1088,11 +1097,8 @@ virJSONValueObjectGetNumberInt(virJSONValuePtr object,
|
|||||||
const char *key,
|
const char *key,
|
||||||
int *value)
|
int *value)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1105,11 +1111,8 @@ virJSONValueObjectGetNumberUint(virJSONValuePtr object,
|
|||||||
const char *key,
|
const char *key,
|
||||||
unsigned int *value)
|
unsigned int *value)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1122,11 +1125,8 @@ virJSONValueObjectGetNumberLong(virJSONValuePtr object,
|
|||||||
const char *key,
|
const char *key,
|
||||||
long long *value)
|
long long *value)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1139,11 +1139,8 @@ virJSONValueObjectGetNumberUlong(virJSONValuePtr object,
|
|||||||
const char *key,
|
const char *key,
|
||||||
unsigned long long *value)
|
unsigned long long *value)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1156,11 +1153,8 @@ virJSONValueObjectGetNumberDouble(virJSONValuePtr object,
|
|||||||
const char *key,
|
const char *key,
|
||||||
double *value)
|
double *value)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -1173,11 +1167,8 @@ virJSONValueObjectGetBoolean(virJSONValuePtr object,
|
|||||||
const char *key,
|
const char *key,
|
||||||
bool *value)
|
bool *value)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
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
|
int
|
||||||
virJSONValueObjectIsNull(virJSONValuePtr object,
|
virJSONValueObjectIsNull(virJSONValuePtr object,
|
||||||
const char *key)
|
const char *key)
|
||||||
{
|
{
|
||||||
virJSONValuePtr val;
|
virJSONValuePtr val = virJSONValueObjectGet(object, key);
|
||||||
if (object->type != VIR_JSON_TYPE_OBJECT)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
val = virJSONValueObjectGet(object, key);
|
|
||||||
if (!val)
|
if (!val)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -110,6 +110,8 @@ int virJSONValueArrayAppend(virJSONValuePtr object, virJSONValuePtr value);
|
|||||||
|
|
||||||
int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key);
|
int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key);
|
||||||
virJSONValuePtr virJSONValueObjectGet(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);
|
bool virJSONValueIsArray(virJSONValuePtr array);
|
||||||
int virJSONValueArraySize(const virJSONValue *array);
|
int virJSONValueArraySize(const virJSONValue *array);
|
||||||
@ -129,7 +131,11 @@ int virJSONValueGetNumberDouble(virJSONValuePtr object, double *value);
|
|||||||
int virJSONValueGetBoolean(virJSONValuePtr object, bool *value);
|
int virJSONValueGetBoolean(virJSONValuePtr object, bool *value);
|
||||||
int virJSONValueGetArrayAsBitmap(const virJSONValue *val, virBitmapPtr *bitmap)
|
int virJSONValueGetArrayAsBitmap(const virJSONValue *val, virBitmapPtr *bitmap)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
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);
|
const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key);
|
||||||
int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value);
|
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
|
static int
|
||||||
testJSONCopy(const void *data)
|
testJSONCopy(const void *data)
|
||||||
{
|
{
|
||||||
@ -319,6 +427,21 @@ mymain(void)
|
|||||||
"[ {[\"key1\", \"key2\"]: \"value\"} ]");
|
"[ {[\"key1\", \"key2\"]: \"value\"} ]");
|
||||||
DO_TEST_PARSE_FAIL("object with unterminated key", "{ \"key:7 }");
|
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;
|
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user