diff options
-rw-r--r-- | docs/qapi-code-gen.txt | 26 | ||||
-rw-r--r-- | include/qapi/error.h | 9 | ||||
-rw-r--r-- | include/qapi/qmp/qobject.h | 1 | ||||
-rw-r--r-- | qapi/introspect.json | 17 | ||||
-rw-r--r-- | scripts/qapi-introspect.py | 8 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 4 | ||||
-rw-r--r-- | tests/qapi-schema/qapi-schema-test.json | 6 | ||||
-rw-r--r-- | tests/qapi-schema/qapi-schema-test.out | 5 | ||||
-rw-r--r-- | tests/test-qmp-commands.c | 3 | ||||
-rw-r--r-- | tests/test-qmp-input-strict.c | 130 | ||||
-rw-r--r-- | tests/test-qmp-input-visitor.c | 271 | ||||
-rw-r--r-- | tests/test-qmp-output-visitor.c | 151 | ||||
-rw-r--r-- | tests/test-visitor-serialization.c | 76 | ||||
-rw-r--r-- | util/error.c | 7 |
14 files changed, 276 insertions, 438 deletions
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 4d8c2fcf02..f9fa6f3d96 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -516,6 +516,10 @@ query-qmp-schema. QGA currently doesn't support introspection. query-qmp-schema returns a JSON array of SchemaInfo objects. These objects together describe the wire ABI, as defined in the QAPI schema. +There is no specified order to the SchemaInfo objects returned; a +client must search for a particular name throughout the entire array +to learn more about that name, but is at least guaranteed that there +will be no collisions between type, command, and event names. However, the SchemaInfo can't reflect all the rules and restrictions that apply to QMP. It's interface introspection (figuring out what's @@ -596,7 +600,9 @@ any. Each element is a JSON object with members "name" (the member's name), "type" (the name of its type), and optionally "default". The member is optional if "default" is present. Currently, "default" can only have value null. Other values are reserved for future -extensions. +extensions. The "members" array is in no particular order; clients +must search the entire object when learning whether a particular +member is supported. Example: the SchemaInfo for MyType from section Struct types @@ -610,7 +616,9 @@ Example: the SchemaInfo for MyType from section Struct types "variants" is a JSON array describing the object's variant members. Each element is a JSON object with members "case" (the value of type tag this element applies to) and "type" (the name of an object type -that provides the variant members for this type tag value). +that provides the variant members for this type tag value). The +"variants" array is in no particular order, and is not guaranteed to +list cases in the same order as the corresponding "tag" enum type. Example: the SchemaInfo for flat union BlockdevOptions from section Union types @@ -651,7 +659,8 @@ Union types The SchemaInfo for an alternate type has meta-type "alternate", and variant member "members". "members" is a JSON array. Each element is a JSON object with member "type", which names a type. Values of the -alternate type conform to exactly one of its member types. +alternate type conform to exactly one of its member types. There is +no guarantee on the order in which "members" will be listed. Example: the SchemaInfo for BlockRef from section Alternate types @@ -662,15 +671,20 @@ Example: the SchemaInfo for BlockRef from section Alternate types The SchemaInfo for an array type has meta-type "array", and variant member "element-type", which names the array's element type. Array -types are implicitly defined. +types are implicitly defined. For convenience, the array's name may +resemble the element type; however, clients should examine member +"element-type" instead of making assumptions based on parsing member +"name". Example: the SchemaInfo for ['str'] - { "name": "strList", "meta-type": "array", + { "name": "[str]", "meta-type": "array", "element-type": "str" } The SchemaInfo for an enumeration type has meta-type "enum" and -variant member "values". +variant member "values". The values are listed in no particular +order; clients must search the entire enum when learning whether a +particular value is supported. Example: the SchemaInfo for MyEnum from section Enumeration types diff --git a/include/qapi/error.h b/include/qapi/error.h index c69dddbbf2..4d42cdc5fd 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -30,6 +30,10 @@ * Handle an error without reporting it (just for completeness): * error_free(err); * + * Assert that an expected error occurred, but clean it up without + * reporting it (primarily useful in testsuites): + * error_free_or_abort(&err); + * * Pass an existing error to the caller: * error_propagate(errp, err); * where Error **errp is a parameter, by convention the last one. @@ -190,6 +194,11 @@ Error *error_copy(const Error *err); void error_free(Error *err); /* + * Convenience function to assert that *@errp is set, then silently free it. + */ +void error_free_or_abort(Error **errp); + +/* * Convenience function to error_report() and free @err. */ void error_report_err(Error *); diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index c856f553b7..4b96ed5837 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -90,6 +90,7 @@ static inline void qobject_incref(QObject *obj) */ static inline void qobject_decref(QObject *obj) { + assert(!obj || obj->refcnt); if (obj && --obj->refcnt == 0) { assert(obj->type != NULL); assert(obj->type->destroy != NULL); diff --git a/qapi/introspect.json b/qapi/introspect.json index cc50dc6bcb..e7c4c3e998 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -25,6 +25,10 @@ # Returns: array of @SchemaInfo, where each element describes an # entity in the ABI: command, event, type, ... # +# The order of the various SchemaInfo is unspecified; however, all +# names are guaranteed to be unique (no name will be duplicated with +# different meta-types). +# # Note: the QAPI schema is also used to help define *internal* # interfaces, by defining QAPI types. These are not part of the QMP # wire ABI, and therefore not returned by this command. @@ -78,7 +82,8 @@ # Commands and events have the name defined in the QAPI schema. # Unlike command and event names, type names are not part of # the wire ABI. Consequently, type names are meaningless -# strings here. +# strings here, although they are still guaranteed unique +# regardless of @meta-type. # # All references to other SchemaInfo are by name. # @@ -130,7 +135,7 @@ # # Additional SchemaInfo members for meta-type 'enum'. # -# @values: the enumeration type's values. +# @values: the enumeration type's values, in no particular order. # # Values of this type are JSON string on the wire. # @@ -158,14 +163,16 @@ # # Additional SchemaInfo members for meta-type 'object'. # -# @members: the object type's (non-variant) members. +# @members: the object type's (non-variant) members, in no particular order. # # @tag: #optional the name of the member serving as type tag. # An element of @members with this name must exist. # # @variants: #optional variant members, i.e. additional members that # depend on the type tag's value. Present exactly when -# @tag is present. +# @tag is present. The variants are in no particular order, +# and may even differ from the order of the values of the +# enum type of the @tag. # # Values of this type are JSON object on the wire. # @@ -219,7 +226,7 @@ # # Additional SchemaInfo members for meta-type 'alternate'. # -# @members: the alternate type's members. +# @members: the alternate type's members, in no particular order. # The members' wire encoding is distinct, see # docs/qapi-code-gen.txt section Alternate types. # diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py index c0dad6679c..64f2cd0631 100644 --- a/scripts/qapi-introspect.py +++ b/scripts/qapi-introspect.py @@ -107,10 +107,12 @@ const char %(c_name)s[] = %(c_string)s; # characters. if isinstance(typ, QAPISchemaBuiltinType): return typ.name + if isinstance(typ, QAPISchemaArrayType): + return '[' + self._use_type(typ.element_type) + ']' return self._name(typ.name) def _gen_json(self, name, mtype, obj): - if mtype != 'command' and mtype != 'event' and mtype != 'builtin': + if mtype not in ('command', 'event', 'builtin', 'array'): name = self._name(name) obj['name'] = name obj['meta-type'] = mtype @@ -136,8 +138,8 @@ const char %(c_name)s[] = %(c_string)s; self._gen_json(name, 'enum', {'values': values}) def visit_array_type(self, name, info, element_type): - self._gen_json(name, 'array', - {'element-type': self._use_type(element_type)}) + element = self._use_type(element_type) + self._gen_json('[' + element + ']', 'array', {'element-type': element}) def visit_object_type_flat(self, name, info, members, variants): obj = {'members': [self._gen_member(m) for m in members]} diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index f40c3c792f..3ef5c16a66 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -138,6 +138,10 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error def gen_visit_list(name, element_type): + # FIXME: if *obj is NULL on entry, and the first visit_next_list() + # assigns to *obj, while a later one fails, we should clean up *obj + # rather than leaving it non-NULL. As currently written, the caller must + # call qapi_free_FOOList() to avoid a memory leak of the partial FOOList. return mcgen(''' void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 48e104ba13..44638da948 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -3,6 +3,9 @@ # This file is a stress test of supported qapi constructs that must # parse and compile correctly. +{ 'struct': 'TestStruct', + 'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } } + # for testing enums { 'struct': 'NestedEnumsOne', 'data': { 'enum1': 'EnumOne', # Intentional forward reference @@ -46,7 +49,8 @@ # dummy struct to force generation of array types not otherwise mentioned { 'struct': 'ForceArrays', - 'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'] } } + 'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'], + 'unused3':['TestStruct'] } } # for testing unions # Among other things, test that a name collision between branches does diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index a7e9aabec0..e20a8239ad 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -92,6 +92,7 @@ object EventStructOne object ForceArrays member unused1: UserDefOneList optional=False member unused2: UserDefTwoList optional=False + member unused3: TestStructList optional=False enum MyEnum [] object NestedEnumsOne member enum1: EnumOne optional=False @@ -100,6 +101,10 @@ object NestedEnumsOne member enum4: EnumOne optional=True enum QEnumTwo ['value1', 'value2'] prefix QENUM_TWO +object TestStruct + member integer: int optional=False + member boolean: bool optional=False + member string: str optional=False object UserDefA member boolean: bool optional=False member a_b: int optional=True diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index f23d8eaf2a..888fb5ffec 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -225,8 +225,7 @@ static void test_dealloc_partial(void) assert(ud2->dict1 == NULL); /* confirm & release construction error */ - assert(err != NULL); - error_free(err); + error_free_or_abort(&err); /* tear down partial object */ qapi_free_UserDefTwo(ud2); diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index 53a769388c..f1c2e3ba67 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -40,31 +40,42 @@ static void validate_teardown(TestInputVisitorData *data, } } -/* This is provided instead of a test setup function so that the JSON - string used by the tests are kept in the test functions (and not - int main()) */ -static GCC_FMT_ATTR(2, 3) -Visitor *validate_test_init(TestInputVisitorData *data, - const char *json_string, ...) +/* The various test_init functions are provided instead of a test setup + function so that the JSON string used by the tests are kept in the test + functions (and not in main()). */ +static Visitor *validate_test_init_internal(TestInputVisitorData *data, + const char *json_string, + va_list *ap) { Visitor *v; - va_list ap; - va_start(ap, json_string); - data->obj = qobject_from_jsonv(json_string, &ap); - va_end(ap); + validate_teardown(data, NULL); - g_assert(data->obj != NULL); + data->obj = qobject_from_jsonv(json_string, ap); + g_assert(data->obj); data->qiv = qmp_input_visitor_new_strict(data->obj); - g_assert(data->qiv != NULL); + g_assert(data->qiv); v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); + g_assert(v); return v; } +static GCC_FMT_ATTR(2, 3) +Visitor *validate_test_init(TestInputVisitorData *data, + const char *json_string, ...) +{ + Visitor *v; + va_list ap; + + va_start(ap, json_string); + v = validate_test_init_internal(data, json_string, &ap); + va_end(ap); + return v; +} + /* similar to validate_test_init(), but does not expect a string * literal/format json_string argument and so can be used for * programatically generated strings (and we can't pass in programatically @@ -75,67 +86,19 @@ Visitor *validate_test_init(TestInputVisitorData *data, static Visitor *validate_test_init_raw(TestInputVisitorData *data, const char *json_string) { - Visitor *v; - - data->obj = qobject_from_json(json_string); - g_assert(data->obj != NULL); - - data->qiv = qmp_input_visitor_new_strict(data->obj); - g_assert(data->qiv != NULL); - - v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); - - return v; + return validate_test_init_internal(data, json_string, NULL); } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (err) { - goto out; - } - - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static void test_validate_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &err); - g_assert(!err); + visit_type_TestStruct(v, &p, NULL, &error_abort); g_free(p->string); g_free(p); } @@ -144,7 +107,6 @@ static void test_validate_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefTwo *udp = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string0': 'string0', " @@ -152,8 +114,7 @@ static void test_validate_struct_nested(TestInputVisitorData *data, "'dict2': { 'userdef': { 'integer': 42, " "'string': 'string' }, 'string': 'string2'}}}"); - visit_type_UserDefTwo(v, &udp, NULL, &err); - g_assert(!err); + visit_type_UserDefTwo(v, &udp, NULL, &error_abort); qapi_free_UserDefTwo(udp); } @@ -161,13 +122,11 @@ static void test_validate_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *head = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &err); - g_assert(!err); + visit_type_UserDefOneList(v, &head, NULL, &error_abort); qapi_free_UserDefOneList(head); } @@ -176,12 +135,10 @@ static void test_validate_union_native_list(TestInputVisitorData *data, { UserDefNativeListUnion *tmp = NULL; Visitor *v; - Error *err = NULL; v = validate_test_init(data, "{ 'type': 'integer', 'data' : [ 1, 2 ] }"); - visit_type_UserDefNativeListUnion(v, &tmp, NULL, &err); - g_assert(!err); + visit_type_UserDefNativeListUnion(v, &tmp, NULL, &error_abort); qapi_free_UserDefNativeListUnion(tmp); } @@ -190,7 +147,6 @@ static void test_validate_union_flat(TestInputVisitorData *data, { UserDefFlatUnion *tmp = NULL; Visitor *v; - Error *err = NULL; v = validate_test_init(data, "{ 'enum1': 'value1', " @@ -198,8 +154,7 @@ static void test_validate_union_flat(TestInputVisitorData *data, "'string': 'str', " "'boolean': true }"); - visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); - g_assert(!err); + visit_type_UserDefFlatUnion(v, &tmp, NULL, &error_abort); qapi_free_UserDefFlatUnion(tmp); } @@ -208,12 +163,10 @@ static void test_validate_alternate(TestInputVisitorData *data, { UserDefAlternate *tmp = NULL; Visitor *v; - Error *err = NULL; v = validate_test_init(data, "42"); - visit_type_UserDefAlternate(v, &tmp, NULL, &err); - g_assert(!err); + visit_type_UserDefAlternate(v, &tmp, NULL, &error_abort); qapi_free_UserDefAlternate(tmp); } @@ -227,7 +180,7 @@ static void test_validate_fail_struct(TestInputVisitorData *data, v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }"); visit_type_TestStruct(v, &p, NULL, &err); - g_assert(err); + error_free_or_abort(&err); if (p) { g_free(p->string); } @@ -244,7 +197,7 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data, v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}"); visit_type_UserDefTwo(v, &udp, NULL, &err); - g_assert(err); + error_free_or_abort(&err); qapi_free_UserDefTwo(udp); } @@ -258,7 +211,7 @@ static void test_validate_fail_list(TestInputVisitorData *data, v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]"); visit_type_UserDefOneList(v, &head, NULL, &err); - g_assert(err); + error_free_or_abort(&err); qapi_free_UserDefOneList(head); } @@ -273,7 +226,7 @@ static void test_validate_fail_union_native_list(TestInputVisitorData *data, "{ 'type': 'integer', 'data' : [ 'string' ] }"); visit_type_UserDefNativeListUnion(v, &tmp, NULL, &err); - g_assert(err); + error_free_or_abort(&err); qapi_free_UserDefNativeListUnion(tmp); } @@ -287,7 +240,7 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data, v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }"); visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); - g_assert(err); + error_free_or_abort(&err); qapi_free_UserDefFlatUnion(tmp); } @@ -302,7 +255,7 @@ static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data, v = validate_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }"); visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err); - g_assert(err); + error_free_or_abort(&err); qapi_free_UserDefFlatUnion2(tmp); } @@ -316,7 +269,7 @@ static void test_validate_fail_alternate(TestInputVisitorData *data, v = validate_test_init(data, "3.14"); visit_type_UserDefAlternate(v, &tmp, NULL, &err); - g_assert(err); + error_free_or_abort(&err); qapi_free_UserDefAlternate(tmp); } @@ -324,16 +277,11 @@ static void do_test_validate_qmp_introspect(TestInputVisitorData *data, const char *schema_json) { SchemaInfoList *schema = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init_raw(data, schema_json); - visit_type_SchemaInfoList(v, &schema, NULL, &err); - if (err) { - fprintf(stderr, "%s", error_get_pretty(err)); - } - g_assert(!err); + visit_type_SchemaInfoList(v, &schema, NULL, &error_abort); g_assert(schema); qapi_free_SchemaInfoList(schema); diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index de65982d47..d48ebdd62f 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -36,28 +36,39 @@ static void visitor_input_teardown(TestInputVisitorData *data, } } -/* This is provided instead of a test setup function so that the JSON - string used by the tests are kept in the test functions (and not - int main()) */ -static GCC_FMT_ATTR(2, 3) -Visitor *visitor_input_test_init(TestInputVisitorData *data, - const char *json_string, ...) +/* The various test_init functions are provided instead of a test setup + function so that the JSON string used by the tests are kept in the test + functions (and not in main()). */ +static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data, + const char *json_string, + va_list *ap) { Visitor *v; - va_list ap; - va_start(ap, json_string); - data->obj = qobject_from_jsonv(json_string, &ap); - va_end(ap); + visitor_input_teardown(data, NULL); - g_assert(data->obj != NULL); + data->obj = qobject_from_jsonv(json_string, ap); + g_assert(data->obj); data->qiv = qmp_input_visitor_new(data->obj); - g_assert(data->qiv != NULL); + g_assert(data->qiv); v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); + g_assert(v); + + return v; +} + +static GCC_FMT_ATTR(2, 3) +Visitor *visitor_input_test_init(TestInputVisitorData *data, + const char *json_string, ...) +{ + Visitor *v; + va_list ap; + va_start(ap, json_string); + v = visitor_input_test_init_internal(data, json_string, &ap); + va_end(ap); return v; } @@ -71,32 +82,18 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data, static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data, const char *json_string) { - Visitor *v; - - data->obj = qobject_from_json(json_string); - - g_assert(data->obj != NULL); - - data->qiv = qmp_input_visitor_new(data->obj); - g_assert(data->qiv != NULL); - - v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); - - return v; + return visitor_input_test_init_internal(data, json_string, NULL); } static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { int64_t res = 0, value = -42; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%" PRId64, value); - visit_type_int(v, &res, NULL, &err); - g_assert(!err); + visit_type_int(v, &res, NULL, &error_abort); g_assert_cmpint(res, ==, value); } @@ -114,21 +111,18 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, v = visitor_input_test_init(data, "%f", DBL_MAX); visit_type_int(v, &res, NULL, &err); - g_assert(err); - error_free(err); + error_free_or_abort(&err); } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &err); - g_assert(!err); + visit_type_bool(v, &res, NULL, &error_abort); g_assert_cmpint(res, ==, true); } @@ -136,13 +130,11 @@ static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { double res = 0, value = 3.14; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%f", value); - visit_type_number(v, &res, NULL, &err); - g_assert(!err); + visit_type_number(v, &res, NULL, &error_abort); g_assert_cmpfloat(res, ==, value); } @@ -150,13 +142,11 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%s", value); - visit_type_str(v, &res, NULL, &err); - g_assert(!err); + visit_type_str(v, &res, NULL, &error_abort); g_assert_cmpstr(res, ==, value); g_free(res); @@ -165,7 +155,6 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *err = NULL; Visitor *v; EnumOne i; @@ -174,63 +163,21 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &err); - g_assert(!err); + visit_type_EnumOne(v, &res, NULL, &error_abort); g_assert_cmpint(i, ==, res); - - visitor_input_teardown(data, NULL); } - - data->obj = NULL; - data->qiv = NULL; } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (err) { - goto out; - } - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static void test_visitor_in_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &err); - g_assert(!err); + visit_type_TestStruct(v, &p, NULL, &error_abort); g_assert_cmpint(p->integer, ==, -42); g_assert(p->boolean == true); g_assert_cmpstr(p->string, ==, "foo"); @@ -239,17 +186,10 @@ static void test_visitor_in_struct(TestInputVisitorData *data, g_free(p); } -static void check_and_free_str(char *str, const char *cmp) -{ - g_assert_cmpstr(str, ==, cmp); - g_free(str); -} - static void test_visitor_in_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefTwo *udp = NULL; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'string0': 'string0', " @@ -257,34 +197,28 @@ static void test_visitor_in_struct_nested(TestInputVisitorData *data, "'dict2': { 'userdef': { 'integer': 42, " "'string': 'string' }, 'string': 'string2'}}}"); - visit_type_UserDefTwo(v, &udp, NULL, &err); - g_assert(!err); + visit_type_UserDefTwo(v, &udp, NULL, &error_abort); - check_and_free_str(udp->string0, "string0"); - check_and_free_str(udp->dict1->string1, "string1"); + g_assert_cmpstr(udp->string0, ==, "string0"); + g_assert_cmpstr(udp->dict1->string1, ==, "string1"); g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42); - check_and_free_str(udp->dict1->dict2->userdef->string, "string"); - check_and_free_str(udp->dict1->dict2->string, "string2"); + g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string"); + g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2"); g_assert(udp->dict1->has_dict3 == false); - g_free(udp->dict1->dict2->userdef); - g_free(udp->dict1->dict2); - g_free(udp->dict1); - g_free(udp); + qapi_free_UserDefTwo(udp); } static void test_visitor_in_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *item, *head = NULL; - Error *err = NULL; Visitor *v; int i; v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &err); - g_assert(!err); + visit_type_UserDefOneList(v, &head, NULL, &error_abort); g_assert(head != NULL); for (i = 0, item = head; item; item = item->next, i++) { @@ -296,13 +230,18 @@ static void test_visitor_in_list(TestInputVisitorData *data, } qapi_free_UserDefOneList(head); + head = NULL; + + /* An empty list is valid */ + v = visitor_input_test_init(data, "[]"); + visit_type_UserDefOneList(v, &head, NULL, &error_abort); + g_assert(!head); } static void test_visitor_in_any(TestInputVisitorData *data, const void *unused) { QObject *res = NULL; - Error *err = NULL; Visitor *v; QInt *qint; QBool *qbool; @@ -311,16 +250,14 @@ static void test_visitor_in_any(TestInputVisitorData *data, QObject *qobj; v = visitor_input_test_init(data, "-42"); - visit_type_any(v, &res, NULL, &err); - g_assert(!err); + visit_type_any(v, &res, NULL, &error_abort); qint = qobject_to_qint(res); g_assert(qint); g_assert_cmpint(qint_get_int(qint), ==, -42); qobject_decref(res); v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_any(v, &res, NULL, &err); - g_assert(!err); + visit_type_any(v, &res, NULL, &error_abort); qdict = qobject_to_qdict(res); g_assert(qdict && qdict_size(qdict) == 3); qobj = qdict_get(qdict, "integer"); @@ -345,7 +282,6 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data, const void *unused) { Visitor *v; - Error *err = NULL; UserDefFlatUnion *tmp; UserDefUnionBase *base; @@ -355,8 +291,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data, "'string': 'str', " "'boolean': true }"); - visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefFlatUnion(v, &tmp, NULL, &error_abort); g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1); g_assert_cmpstr(tmp->string, ==, "str"); g_assert_cmpint(tmp->integer, ==, 41); @@ -380,22 +315,17 @@ static void test_visitor_in_alternate(TestInputVisitorData *data, g_assert_cmpint(tmp->type, ==, USER_DEF_ALTERNATE_KIND_I); g_assert_cmpint(tmp->u.i, ==, 42); qapi_free_UserDefAlternate(tmp); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "'string'"); visit_type_UserDefAlternate(v, &tmp, NULL, &error_abort); g_assert_cmpint(tmp->type, ==, USER_DEF_ALTERNATE_KIND_S); g_assert_cmpstr(tmp->u.s, ==, "string"); qapi_free_UserDefAlternate(tmp); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "false"); visit_type_UserDefAlternate(v, &tmp, NULL, &err); - g_assert(err); - error_free(err); - err = NULL; + error_free_or_abort(&err); qapi_free_UserDefAlternate(tmp); - visitor_input_teardown(data, NULL); } static void test_visitor_in_alternate_number(TestInputVisitorData *data, @@ -414,11 +344,8 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data, v = visitor_input_test_init(data, "42"); visit_type_AltStrBool(v, &asb, NULL, &err); - g_assert(err); - error_free(err); - err = NULL; + error_free_or_abort(&err); qapi_free_AltStrBool(asb); - visitor_input_teardown(data, NULL); /* FIXME: Order of alternate should not affect semantics; asn should * parse the same as ans */ @@ -426,85 +353,68 @@ static void test_visitor_in_alternate_number(TestInputVisitorData *data, visit_type_AltStrNum(v, &asn, NULL, &err); /* FIXME g_assert_cmpint(asn->type, == ALT_STR_NUM_KIND_N); */ /* FIXME g_assert_cmpfloat(asn->u.n, ==, 42); */ - g_assert(err); - error_free(err); - err = NULL; + error_free_or_abort(&err); qapi_free_AltStrNum(asn); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42"); visit_type_AltNumStr(v, &ans, NULL, &error_abort); g_assert_cmpint(ans->type, ==, ALT_NUM_STR_KIND_N); g_assert_cmpfloat(ans->u.n, ==, 42); qapi_free_AltNumStr(ans); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42"); visit_type_AltStrInt(v, &asi, NULL, &error_abort); g_assert_cmpint(asi->type, ==, ALT_STR_INT_KIND_I); g_assert_cmpint(asi->u.i, ==, 42); qapi_free_AltStrInt(asi); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42"); visit_type_AltIntNum(v, &ain, NULL, &error_abort); g_assert_cmpint(ain->type, ==, ALT_INT_NUM_KIND_I); g_assert_cmpint(ain->u.i, ==, 42); qapi_free_AltIntNum(ain); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42"); visit_type_AltNumInt(v, &ani, NULL, &error_abort); g_assert_cmpint(ani->type, ==, ALT_NUM_INT_KIND_I); g_assert_cmpint(ani->u.i, ==, 42); qapi_free_AltNumInt(ani); - visitor_input_teardown(data, NULL); /* Parsing a double */ v = visitor_input_test_init(data, "42.5"); visit_type_AltStrBool(v, &asb, NULL, &err); - g_assert(err); - error_free(err); - err = NULL; + error_free_or_abort(&err); qapi_free_AltStrBool(asb); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42.5"); visit_type_AltStrNum(v, &asn, NULL, &error_abort); g_assert_cmpint(asn->type, ==, ALT_STR_NUM_KIND_N); g_assert_cmpfloat(asn->u.n, ==, 42.5); qapi_free_AltStrNum(asn); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42.5"); visit_type_AltNumStr(v, &ans, NULL, &error_abort); g_assert_cmpint(ans->type, ==, ALT_NUM_STR_KIND_N); g_assert_cmpfloat(ans->u.n, ==, 42.5); qapi_free_AltNumStr(ans); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42.5"); visit_type_AltStrInt(v, &asi, NULL, &err); - g_assert(err); - error_free(err); - err = NULL; + error_free_or_abort(&err); qapi_free_AltStrInt(asi); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42.5"); visit_type_AltIntNum(v, &ain, NULL, &error_abort); g_assert_cmpint(ain->type, ==, ALT_INT_NUM_KIND_N); g_assert_cmpfloat(ain->u.n, ==, 42.5); qapi_free_AltIntNum(ain); - visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, "42.5"); visit_type_AltNumInt(v, &ani, NULL, &error_abort); g_assert_cmpint(ani->type, ==, ALT_NUM_INT_KIND_N); g_assert_cmpfloat(ani->u.n, ==, 42.5); qapi_free_AltNumInt(ani); - visitor_input_teardown(data, NULL); } static void test_native_list_integer_helper(TestInputVisitorData *data, @@ -512,7 +422,6 @@ static void test_native_list_integer_helper(TestInputVisitorData *data, UserDefNativeListUnionKind kind) { UserDefNativeListUnion *cvalue = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -529,8 +438,7 @@ static void test_native_list_integer_helper(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &error_abort); g_assert(cvalue != NULL); g_assert_cmpint(cvalue->type, ==, kind); @@ -675,7 +583,6 @@ static void test_visitor_in_native_list_bool(TestInputVisitorData *data, { UserDefNativeListUnion *cvalue = NULL; boolList *elem = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -692,8 +599,7 @@ static void test_visitor_in_native_list_bool(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &error_abort); g_assert(cvalue != NULL); g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN); @@ -711,7 +617,6 @@ static void test_visitor_in_native_list_string(TestInputVisitorData *data, { UserDefNativeListUnion *cvalue = NULL; strList *elem = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -727,8 +632,7 @@ static void test_visitor_in_native_list_string(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &error_abort); g_assert(cvalue != NULL); g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING); @@ -750,7 +654,6 @@ static void test_visitor_in_native_list_number(TestInputVisitorData *data, { UserDefNativeListUnion *cvalue = NULL; numberList *elem = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -766,8 +669,7 @@ static void test_visitor_in_native_list_number(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &error_abort); g_assert(cvalue != NULL); g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER); @@ -802,18 +704,69 @@ static void test_visitor_in_errors(TestInputVisitorData *data, TestStruct *p = NULL; Error *err = NULL; Visitor *v; + strList *q = NULL; - v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }"); + v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', " + "'string': -42 }"); visit_type_TestStruct(v, &p, NULL, &err); - g_assert(err); + error_free_or_abort(&err); /* FIXME - a failed parse should not leave a partially-allocated p * for us to clean up; this could cause callers to leak memory. */ g_assert(p->string == NULL); - error_free(err); g_free(p->string); g_free(p); + + v = visitor_input_test_init(data, "[ '1', '2', false, '3' ]"); + visit_type_strList(v, &q, NULL, &err); + error_free_or_abort(&err); + assert(q); + qapi_free_strList(q); +} + +static void test_visitor_in_wrong_type(TestInputVisitorData *data, + const void *unused) +{ + TestStruct *p = NULL; + Visitor *v; + strList *q = NULL; + int64_t i; + Error *err = NULL; + + /* Make sure arrays and structs cannot be confused */ + + v = visitor_input_test_init(data, "[]"); + visit_type_TestStruct(v, &p, NULL, &err); + error_free_or_abort(&err); + g_assert(!p); + + v = visitor_input_test_init(data, "{}"); + visit_type_strList(v, &q, NULL, &err); + error_free_or_abort(&err); + assert(!q); + + /* Make sure primitives and struct cannot be confused */ + + v = visitor_input_test_init(data, "1"); + visit_type_TestStruct(v, &p, NULL, &err); + error_free_or_abort(&err); + g_assert(!p); + + v = visitor_input_test_init(data, "{}"); + visit_type_int(v, &i, NULL, &err); + error_free_or_abort(&err); + + /* Make sure primitives and arrays cannot be confused */ + + v = visitor_input_test_init(data, "1"); + visit_type_strList(v, &q, NULL, &err); + error_free_or_abort(&err); + assert(!q); + + v = visitor_input_test_init(data, "[]"); + visit_type_int(v, &i, NULL, &err); + error_free_or_abort(&err); } int main(int argc, char **argv) @@ -848,6 +801,8 @@ int main(int argc, char **argv) &in_visitor_data, test_visitor_in_alternate); input_visitor_test_add("/visitor/input/errors", &in_visitor_data, test_visitor_in_errors); + input_visitor_test_add("/visitor/input/wrong-type", + &in_visitor_data, test_visitor_in_wrong_type); input_visitor_test_add("/visitor/input/alternate-number", &in_visitor_data, test_visitor_in_alternate_number); input_visitor_test_add("/visitor/input/native_list/int", diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index 09d0dd81f0..0d0c85989a 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -45,11 +45,9 @@ static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { int64_t value = -42; - Error *err = NULL; QObject *obj; - visit_type_int(data->ov, &value, NULL, &err); - g_assert(!err); + visit_type_int(data->ov, &value, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -62,12 +60,10 @@ static void test_visitor_out_int(TestOutputVisitorData *data, static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *err = NULL; bool value = true; QObject *obj; - visit_type_bool(data->ov, &value, NULL, &err); - g_assert(!err); + visit_type_bool(data->ov, &value, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -81,11 +77,9 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *err = NULL; QObject *obj; - visit_type_number(data->ov, &value, NULL, &err); - g_assert(!err); + visit_type_number(data->ov, &value, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -99,11 +93,9 @@ static void test_visitor_out_string(TestOutputVisitorData *data, const void *unused) { char *string = (char *) "Q E M U"; - Error *err = NULL; QObject *obj; - visit_type_str(data->ov, &string, NULL, &err); - g_assert(!err); + visit_type_str(data->ov, &string, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -117,12 +109,10 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, const void *unused) { char *string = NULL; - Error *err = NULL; QObject *obj; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &err); - g_assert(!err); + visit_type_str(data->ov, &string, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -135,13 +125,11 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, static void test_visitor_out_enum(TestOutputVisitorData *data, const void *unused) { - Error *err = NULL; QObject *obj; EnumOne i; for (i = 0; i < ENUM_ONE_MAX; i++) { - visit_type_EnumOne(data->ov, &i, "unused", &err); - g_assert(!err); + visit_type_EnumOne(data->ov, &i, "unused", &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -166,41 +154,6 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data, } } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (err) { - goto out; - } - - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static void test_visitor_out_struct(TestOutputVisitorData *data, const void *unused) @@ -209,12 +162,10 @@ static void test_visitor_out_struct(TestOutputVisitorData *data, .boolean = false, .string = (char *) "foo"}; TestStruct *p = &test_struct; - Error *err = NULL; QObject *obj; QDict *qdict; - visit_type_TestStruct(data->ov, &p, NULL, &err); - g_assert(!err); + visit_type_TestStruct(data->ov, &p, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -233,7 +184,6 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, const void *unused) { int64_t value = 42; - Error *err = NULL; UserDefTwo *ud2; QObject *obj; QDict *qdict, *dict1, *dict2, *dict3, *userdef; @@ -260,8 +210,7 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, ud2->dict1->dict3->userdef->integer = value; ud2->dict1->dict3->string = g_strdup(strings[3]); - visit_type_UserDefTwo(data->ov, &ud2, "unused", &err); - g_assert(!err); + visit_type_UserDefTwo(data->ov, &ud2, "unused", &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -314,57 +263,33 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data, } } -typedef struct TestStructList -{ - union { - TestStruct *value; - uint64_t padding; - }; - struct TestStructList *next; -} TestStructList; - -static void visit_type_TestStructList(Visitor *v, TestStructList **obj, - const char *name, Error **errp) -{ - GenericList *i, **head = (GenericList **)obj; - - visit_start_list(v, name, errp); - - for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) { - TestStructList *native_i = (TestStructList *)i; - visit_type_TestStruct(v, &native_i->value, NULL, errp); - } - - visit_end_list(v, errp); -} static void test_visitor_out_list(TestOutputVisitorData *data, const void *unused) { - char *value_str = (char *) "list value"; + const char *value_str = "list value"; TestStructList *p, *head = NULL; const int max_items = 10; bool value_bool = true; int value_int = 10; - Error *err = NULL; QListEntry *entry; QObject *obj; QList *qlist; int i; + /* Build the list in reverse order... */ for (i = 0; i < max_items; i++) { p = g_malloc0(sizeof(*p)); p->value = g_malloc0(sizeof(*p->value)); - p->value->integer = value_int; + p->value->integer = value_int + (max_items - i - 1); p->value->boolean = value_bool; - p->value->string = value_str; + p->value->string = g_strdup(value_str); p->next = head; head = p; } - visit_type_TestStructList(data->ov, &head, NULL, &err); - g_assert(!err); + visit_type_TestStructList(data->ov, &head, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -373,6 +298,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, qlist = qobject_to_qlist(obj); g_assert(!qlist_empty(qlist)); + /* ...and ensure that the visitor sees it in order */ i = 0; QLIST_FOREACH_ENTRY(qlist, entry) { QDict *qdict; @@ -380,7 +306,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, g_assert(qobject_type(entry->value) == QTYPE_QDICT); qdict = qobject_to_qdict(entry->value); g_assert_cmpint(qdict_size(qdict), ==, 3); - g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int); + g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int + i); g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool); g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str); i++; @@ -388,13 +314,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, g_assert_cmpint(i, ==, max_items); QDECREF(qlist); - - for (p = head; p;) { - TestStructList *tmp = p->next; - g_free(p->value); - g_free(p); - p = tmp; - } + qapi_free_TestStructList(head); } static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, @@ -429,7 +349,6 @@ static void test_visitor_out_any(TestOutputVisitorData *data, const void *unused) { QObject *qobj; - Error *err = NULL; QInt *qint; QBool *qbool; QString *qstring; @@ -437,8 +356,7 @@ static void test_visitor_out_any(TestOutputVisitorData *data, QObject *obj; qobj = QOBJECT(qint_from_int(-42)); - visit_type_any(data->ov, &qobj, NULL, &err); - g_assert(!err); + visit_type_any(data->ov, &qobj, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); g_assert(qobject_type(obj) == QTYPE_QINT); @@ -451,8 +369,8 @@ static void test_visitor_out_any(TestOutputVisitorData *data, qdict_put(qdict, "boolean", qbool_from_bool(true)); qdict_put(qdict, "string", qstring_from_str("foo")); qobj = QOBJECT(qdict); - visit_type_any(data->ov, &qobj, NULL, &err); - g_assert(!err); + visit_type_any(data->ov, &qobj, NULL, &error_abort); + qobject_decref(qobj); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); qdict = qobject_to_qdict(obj); @@ -473,7 +391,6 @@ static void test_visitor_out_any(TestOutputVisitorData *data, g_assert(qstring); g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); qobject_decref(obj); - qobject_decref(qobj); } static void test_visitor_out_union_flat(TestOutputVisitorData *data, @@ -482,8 +399,6 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data, QObject *arg; QDict *qdict; - Error *err = NULL; - UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion)); tmp->enum1 = ENUM_ONE_VALUE1; tmp->string = g_strdup("str"); @@ -491,8 +406,7 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data, tmp->integer = 41; tmp->u.value1->boolean = true; - visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &error_abort); arg = qmp_output_get_qobject(data->qov); g_assert(qobject_type(arg) == QTYPE_QDICT); @@ -511,20 +425,33 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, const void *unused) { QObject *arg; - Error *err = NULL; + UserDefAlternate *tmp; - UserDefAlternate *tmp = g_malloc0(sizeof(UserDefAlternate)); + tmp = g_new0(UserDefAlternate, 1); tmp->type = USER_DEF_ALTERNATE_KIND_I; tmp->u.i = 42; - visit_type_UserDefAlternate(data->ov, &tmp, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefAlternate(data->ov, &tmp, NULL, &error_abort); arg = qmp_output_get_qobject(data->qov); g_assert(qobject_type(arg) == QTYPE_QINT); g_assert_cmpint(qint_get_int(qobject_to_qint(arg)), ==, 42); qapi_free_UserDefAlternate(tmp); + qobject_decref(arg); + + tmp = g_new0(UserDefAlternate, 1); + tmp->type = USER_DEF_ALTERNATE_KIND_S; + tmp->u.s = g_strdup("hello"); + + visit_type_UserDefAlternate(data->ov, &tmp, NULL, &error_abort); + arg = qmp_output_get_qobject(data->qov); + + g_assert(qobject_type(arg) == QTYPE_QSTRING); + g_assert_cmpstr(qstring_get_str(qobject_to_qstring(arg)), ==, "hello"); + + qapi_free_UserDefAlternate(tmp); + qobject_decref(arg); } static void test_visitor_out_empty(TestOutputVisitorData *data, @@ -758,14 +685,12 @@ static void test_native_list(TestOutputVisitorData *data, UserDefNativeListUnionKind kind) { UserDefNativeListUnion *cvalue = g_new0(UserDefNativeListUnion, 1); - Error *err = NULL; QObject *obj; cvalue->type = kind; init_native_list(cvalue); - visit_type_UserDefNativeListUnion(data->ov, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(data->ov, &cvalue, NULL, &error_abort); obj = qmp_output_get_qobject(data->qov); check_native_list(obj, cvalue->type); diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index 634563bae4..9f67f9e003 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -186,40 +186,6 @@ static void visit_primitive_list(Visitor *v, void **native, Error **errp) } } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err); - if (err) { - goto out; - } - - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static TestStruct *struct_create(void) { @@ -336,14 +302,13 @@ static void test_primitives(gconstpointer opaque) const SerializeOps *ops = args->ops; PrimitiveType *pt = args->test_data; PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); - Error *err = NULL; void *serialize_data; pt_copy->type = pt->type; - ops->serialize(pt, &serialize_data, visit_primitive_type, &err); - ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, &err); + ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort); + ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, + &error_abort); - g_assert(err == NULL); g_assert(pt_copy != NULL); if (pt->type == PTYPE_STRING) { g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); @@ -379,7 +344,6 @@ static void test_primitive_lists(gconstpointer opaque) PrimitiveList pl = { .value = { NULL } }; PrimitiveList pl_copy = { .value = { NULL } }; PrimitiveList *pl_copy_ptr = &pl_copy; - Error *err = NULL; void *serialize_data; void *cur_head = NULL; int i; @@ -526,10 +490,11 @@ static void test_primitive_lists(gconstpointer opaque) } } - ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, &err); - ops->deserialize((void **)&pl_copy_ptr, serialize_data, visit_primitive_list, &err); + ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, + &error_abort); + ops->deserialize((void **)&pl_copy_ptr, serialize_data, + visit_primitive_list, &error_abort); - g_assert(err == NULL); i = 0; /* compare our deserialized list of primitives to the original */ @@ -686,10 +651,8 @@ static void test_primitive_lists(gconstpointer opaque) g_assert_cmpint(i, ==, 33); ops->cleanup(serialize_data); - dealloc_helper(&pl, visit_primitive_list, &err); - g_assert(!err); - dealloc_helper(&pl_copy, visit_primitive_list, &err); - g_assert(!err); + dealloc_helper(&pl, visit_primitive_list, &error_abort); + dealloc_helper(&pl_copy, visit_primitive_list, &error_abort); g_free(args); } @@ -699,13 +662,12 @@ static void test_struct(gconstpointer opaque) const SerializeOps *ops = args->ops; TestStruct *ts = struct_create(); TestStruct *ts_copy = NULL; - Error *err = NULL; void *serialize_data; - ops->serialize(ts, &serialize_data, visit_struct, &err); - ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, &err); + ops->serialize(ts, &serialize_data, visit_struct, &error_abort); + ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, + &error_abort); - g_assert(err == NULL); struct_compare(ts, ts_copy); struct_cleanup(ts); @@ -721,14 +683,12 @@ static void test_nested_struct(gconstpointer opaque) const SerializeOps *ops = args->ops; UserDefTwo *udnp = nested_struct_create(); UserDefTwo *udnp_copy = NULL; - Error *err = NULL; void *serialize_data; - ops->serialize(udnp, &serialize_data, visit_nested_struct, &err); + ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort); ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, - &err); + &error_abort); - g_assert(err == NULL); nested_struct_compare(udnp, udnp_copy); nested_struct_cleanup(udnp); @@ -743,7 +703,6 @@ static void test_nested_struct_list(gconstpointer opaque) TestArgs *args = (TestArgs *) opaque; const SerializeOps *ops = args->ops; UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL; - Error *err = NULL; void *serialize_data; int i = 0; @@ -754,11 +713,10 @@ static void test_nested_struct_list(gconstpointer opaque) listp = tmp; } - ops->serialize(listp, &serialize_data, visit_nested_struct_list, &err); + ops->serialize(listp, &serialize_data, visit_nested_struct_list, + &error_abort); ops->deserialize((void **)&listp_copy, serialize_data, - visit_nested_struct_list, &err); - - g_assert(err == NULL); + visit_nested_struct_list, &error_abort); tmp = listp; tmp_copy = listp_copy; diff --git a/util/error.c b/util/error.c index 8b86490ba1..80c89a2079 100644 --- a/util/error.c +++ b/util/error.c @@ -220,6 +220,13 @@ void error_free(Error *err) } } +void error_free_or_abort(Error **errp) +{ + assert(errp && *errp); + error_free(*errp); + *errp = NULL; +} + void error_propagate(Error **dst_errp, Error *local_err) { if (!local_err) { |