diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 94c02abfe05f33befbb071a33e8a1a7f2a3dae00..cdd0b41baaaf86c0f88690647f3584411f63e1a8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1427,6 +1427,7 @@ virJSONValueObjectGetValue; virJSONValueObjectHasKey; virJSONValueObjectIsNull; virJSONValueObjectKeysNumber; +virJSONValueObjectRemoveKey; virJSONValueToString; diff --git a/src/util/virjson.c b/src/util/virjson.c index 92138d36730b652cc57e213c3fc8c82ee92db676..9410b664db1ab0bedf533b75270b3f4bc804c35d 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1,7 +1,7 @@ /* * virjson.c: JSON object parsing/formatting * - * Copyright (C) 2009-2010, 2012 Red Hat, Inc. + * Copyright (C) 2009-2010, 2012-2013 Red Hat, Inc. * Copyright (C) 2009 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -448,6 +448,38 @@ const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n) return object->data.object.pairs[n].key; } +/* Remove the key-value pair tied to @key out of @object. If @value is + * not NULL, the dropped value object is returned instead of freed. + * Returns 1 on success, 0 if no key was found, and -1 on error. */ +int +virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key, + virJSONValuePtr *value) +{ + int i; + + if (value) + *value = NULL; + + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + for (i = 0 ; i < object->data.object.npairs ; i++) { + if (STREQ(object->data.object.pairs[i].key, key)) { + if (value) { + *value = object->data.object.pairs[i].value; + object->data.object.pairs[i].value = NULL; + } + VIR_FREE(object->data.object.pairs[i].key); + virJSONValueFree(object->data.object.pairs[i].value); + VIR_DELETE_ELEMENT(object->data.object.pairs, i, + object->data.object.npairs); + return 1; + } + } + + return 0; +} + virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n) { if (object->type != VIR_JSON_TYPE_OBJECT) diff --git a/src/util/virjson.h b/src/util/virjson.h index 67f4398f436a2a6be60217ff7663d4aff3ac6e33..db11396258081db59fd91653453d62ac6d494eb0 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -1,7 +1,7 @@ /* * virjson.h: JSON object parsing/formatting * - * Copyright (C) 2009, 2012 Red Hat, Inc. + * Copyright (C) 2009, 2012-2013 Red Hat, Inc. * Copyright (C) 2009 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -55,12 +55,12 @@ struct _virJSONObjectPair { }; struct _virJSONObject { - unsigned int npairs; + size_t npairs; virJSONObjectPairPtr pairs; }; struct _virJSONArray { - unsigned int nvalues; + size_t nvalues; virJSONValuePtr *values; }; @@ -131,6 +131,10 @@ int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean); int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key); +int virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key, + virJSONValuePtr *value) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + virJSONValuePtr virJSONValueFromString(const char *jsonstring); char *virJSONValueToString(virJSONValuePtr object, bool pretty); diff --git a/tests/jsontest.c b/tests/jsontest.c index 98a60690f8d9bb79de359f1a7707d12fb3887701..a37a98023879b2f1d17c5a942a481476cb0054d7 100644 --- a/tests/jsontest.c +++ b/tests/jsontest.c @@ -11,6 +11,7 @@ struct testInfo { const char *doc; + const char *expect; bool pass; }; @@ -54,20 +55,89 @@ cleanup: } +static int +testJSONAddRemove(const void *data) +{ + const struct testInfo *info = data; + virJSONValuePtr json; + virJSONValuePtr name; + char *result = NULL; + int ret = -1; + + json = virJSONValueFromString(info->doc); + + switch (virJSONValueObjectRemoveKey(json, "name", &name)) { + case 1: + if (!info->pass) { + if (virTestGetVerbose()) + fprintf(stderr, "should not remove from non-object %s\n", + info->doc); + goto cleanup; + } + break; + case -1: + if (!info->pass) + ret = 0; + else if (virTestGetVerbose()) + fprintf(stderr, "Fail to recognize non-object %s\n", info->doc); + goto cleanup; + default: + if (virTestGetVerbose()) + fprintf(stderr, "unexpected result when removing from %s\n", + info->doc); + goto cleanup; + } + if (STRNEQ_NULLABLE(virJSONValueGetString(name), "sample")) { + if (virTestGetVerbose()) + fprintf(stderr, "unexpected value after removing name: %s\n", + NULLSTR(virJSONValueGetString(name))); + goto cleanup; + } + if (virJSONValueObjectRemoveKey(json, "name", NULL)) { + if (virTestGetVerbose()) + fprintf(stderr, "%s", + "unexpected success when removing missing key\n"); + goto cleanup; + } + if (virJSONValueObjectAppendString(json, "newname", "foo") < 0) { + if (virTestGetVerbose()) + fprintf(stderr, "%s", "unexpected failure adding new key\n"); + goto cleanup; + } + if (!(result = virJSONValueToString(json, false))) { + if (virTestGetVerbose()) + fprintf(stderr, "%s", "failed to stringize result\n"); + goto cleanup; + } + if (STRNEQ(info->expect, result)) { + if (virTestGetVerbose()) + virtTestDifference(stderr, info->expect, result); + goto cleanup; + } + ret = 0; + +cleanup: + virJSONValueFree(json); + virJSONValueFree(name); + VIR_FREE(result); + return ret; +} + + static int mymain(void) { int ret = 0; -#define DO_TEST_FULL(name, cmd, doc, pass) \ +#define DO_TEST_FULL(name, cmd, doc, expect, pass) \ do { \ - struct testInfo info = { doc, pass }; \ + struct testInfo info = { doc, expect, pass }; \ if (virtTestRun(name, 1, testJSON ## cmd, &info) < 0) \ ret = -1; \ } while (0) #define DO_TEST_PARSE(name, doc) \ - DO_TEST_FULL(name, FromString, doc, true) + DO_TEST_FULL(name, FromString, doc, NULL, true) DO_TEST_PARSE("Simple", "{\"return\": {}, \"id\": \"libvirt-1\"}"); DO_TEST_PARSE("NotSoSimple", "{\"QMP\": {\"version\": {\"qemu\":" @@ -105,6 +175,13 @@ mymain(void) "\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": " "\"query-balloon\"}], \"id\": \"libvirt-2\"}"); + DO_TEST_FULL("add and remove", AddRemove, + "{\"name\": \"sample\", \"value\": true}", + "{\"value\":true,\"newname\":\"foo\"}", + true); + DO_TEST_FULL("add and remove", AddRemove, + "[ 1 ]", NULL, false); + return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }