Merge remote-tracking branch 'bonzini/qdev-props-for-anthony' into staging
* bonzini/qdev-props-for-anthony: qdev: drop unnecessary parse/print methods qdev: use built-in QOM string parser qdev: accept hex properties only if prefixed by 0x qdev: accept both strings and integers for PCI addresses qom: add generic string parsing/printing qapi: add tests for string-based visitors qapi: add string-based visitors qapi: drop qmp_input_end_optional qapi: allow sharing enum implementation across visitors
This commit is contained in:
commit
4732dcaf5a
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -44,6 +44,8 @@ QMP/qmp-commands.txt
|
|||
test-coroutine
|
||||
test-qmp-input-visitor
|
||||
test-qmp-output-visitor
|
||||
test-string-input-visitor
|
||||
test-string-output-visitor
|
||||
fsdev/virtfs-proxy-helper.1
|
||||
fsdev/virtfs-proxy-helper.pod
|
||||
.gdbinit
|
||||
|
|
|
@ -412,8 +412,9 @@ libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o
|
|||
######################################################################
|
||||
# qapi
|
||||
|
||||
qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
|
||||
qapi-nested-y += qmp-registry.o qmp-dispatch.o
|
||||
qapi-nested-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
|
||||
qapi-nested-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
|
||||
qapi-nested-y += string-input-visitor.o string-output-visitor.o
|
||||
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
|
||||
|
||||
common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y)
|
||||
|
|
|
@ -27,16 +27,6 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val)
|
|||
}
|
||||
|
||||
/* Bit */
|
||||
static int parse_bit(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
if (!strcasecmp(str, "on"))
|
||||
bit_prop_set(dev, prop, true);
|
||||
else if (!strcasecmp(str, "off"))
|
||||
bit_prop_set(dev, prop, false);
|
||||
else
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
|
@ -79,7 +69,6 @@ static void set_bit(Object *obj, Visitor *v, void *opaque,
|
|||
PropertyInfo qdev_prop_bit = {
|
||||
.name = "boolean",
|
||||
.legacy_name = "on/off",
|
||||
.parse = parse_bit,
|
||||
.print = print_bit,
|
||||
.get = get_bit,
|
||||
.set = set_bit,
|
||||
|
@ -87,26 +76,6 @@ PropertyInfo qdev_prop_bit = {
|
|||
|
||||
/* --- 8bit integer --- */
|
||||
|
||||
static int parse_uint8(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
/* accept both hex and decimal */
|
||||
*ptr = strtoul(str, &end, 0);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
return snprintf(dest, len, "%" PRIu8, *ptr);
|
||||
}
|
||||
|
||||
static void get_int8(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
|
@ -149,8 +118,6 @@ static void set_int8(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint8 = {
|
||||
.name = "uint8",
|
||||
.parse = parse_uint8,
|
||||
.print = print_uint8,
|
||||
.get = get_int8,
|
||||
.set = set_int8,
|
||||
.min = 0,
|
||||
|
@ -164,6 +131,10 @@ static int parse_hex8(DeviceState *dev, Property *prop, const char *str)
|
|||
uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
if (str[0] != '0' || str[1] != 'x') {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ptr = strtoul(str, &end, 16);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
|
@ -191,26 +162,6 @@ PropertyInfo qdev_prop_hex8 = {
|
|||
|
||||
/* --- 16bit integer --- */
|
||||
|
||||
static int parse_uint16(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
/* accept both hex and decimal */
|
||||
*ptr = strtoul(str, &end, 0);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
return snprintf(dest, len, "%" PRIu16, *ptr);
|
||||
}
|
||||
|
||||
static void get_int16(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
|
@ -253,8 +204,6 @@ static void set_int16(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint16 = {
|
||||
.name = "uint16",
|
||||
.parse = parse_uint16,
|
||||
.print = print_uint16,
|
||||
.get = get_int16,
|
||||
.set = set_int16,
|
||||
.min = 0,
|
||||
|
@ -263,26 +212,6 @@ PropertyInfo qdev_prop_uint16 = {
|
|||
|
||||
/* --- 32bit integer --- */
|
||||
|
||||
static int parse_uint32(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
/* accept both hex and decimal */
|
||||
*ptr = strtoul(str, &end, 0);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
return snprintf(dest, len, "%" PRIu32, *ptr);
|
||||
}
|
||||
|
||||
static void get_int32(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
|
@ -325,37 +254,14 @@ static void set_int32(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint32 = {
|
||||
.name = "uint32",
|
||||
.parse = parse_uint32,
|
||||
.print = print_uint32,
|
||||
.get = get_int32,
|
||||
.set = set_int32,
|
||||
.min = 0,
|
||||
.max = 0xFFFFFFFFULL,
|
||||
};
|
||||
|
||||
static int parse_int32(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
*ptr = strtol(str, &end, 10);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
return snprintf(dest, len, "%" PRId32, *ptr);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_int32 = {
|
||||
.name = "int32",
|
||||
.parse = parse_int32,
|
||||
.print = print_int32,
|
||||
.get = get_int32,
|
||||
.set = set_int32,
|
||||
.min = -0x80000000LL,
|
||||
|
@ -369,6 +275,10 @@ static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
|
|||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
if (str[0] != '0' || str[1] != 'x') {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ptr = strtoul(str, &end, 16);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
|
@ -396,26 +306,6 @@ PropertyInfo qdev_prop_hex32 = {
|
|||
|
||||
/* --- 64bit integer --- */
|
||||
|
||||
static int parse_uint64(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
/* accept both hex and decimal */
|
||||
*ptr = strtoull(str, &end, 0);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
return snprintf(dest, len, "%" PRIu64, *ptr);
|
||||
}
|
||||
|
||||
static void get_int64(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
|
@ -443,8 +333,6 @@ static void set_int64(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_uint64 = {
|
||||
.name = "uint64",
|
||||
.parse = parse_uint64,
|
||||
.print = print_uint64,
|
||||
.get = get_int64,
|
||||
.set = set_int64,
|
||||
};
|
||||
|
@ -456,6 +344,10 @@ static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
|
|||
uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
char *end;
|
||||
|
||||
if (str[0] != '0' || str[1] != 'x') {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ptr = strtoull(str, &end, 16);
|
||||
if ((*end != '\0') || (end == str)) {
|
||||
return -EINVAL;
|
||||
|
@ -737,19 +629,6 @@ PropertyInfo qdev_prop_netdev = {
|
|||
|
||||
/* --- vlan --- */
|
||||
|
||||
static int parse_vlan(DeviceState *dev, Property *prop, const char *str)
|
||||
{
|
||||
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
int id;
|
||||
|
||||
if (sscanf(str, "%d", &id) != 1)
|
||||
return -EINVAL;
|
||||
*ptr = qemu_find_vlan(id, 1);
|
||||
if (*ptr == NULL)
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
{
|
||||
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||
|
@ -808,7 +687,6 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque,
|
|||
|
||||
PropertyInfo qdev_prop_vlan = {
|
||||
.name = "vlan",
|
||||
.parse = parse_vlan,
|
||||
.print = print_vlan,
|
||||
.get = get_vlan,
|
||||
.set = set_vlan,
|
||||
|
@ -943,25 +821,40 @@ PropertyInfo qdev_prop_losttickpolicy = {
|
|||
/*
|
||||
* bus-local address, i.e. "$slot" or "$slot.$fn"
|
||||
*/
|
||||
static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
|
||||
static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Property *prop = opaque;
|
||||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
unsigned int slot, fn, n;
|
||||
Error *local_err = NULL;
|
||||
char *str = (char *)"";
|
||||
|
||||
if (dev->state != DEV_STATE_CREATED) {
|
||||
error_set(errp, QERR_PERMISSION_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, &str, name, &local_err);
|
||||
if (local_err) {
|
||||
return set_int32(obj, v, opaque, name, errp);
|
||||
}
|
||||
|
||||
if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
|
||||
fn = 0;
|
||||
if (sscanf(str, "%x%n", &slot, &n) != 1) {
|
||||
return -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
if (str[n] != '\0')
|
||||
return -EINVAL;
|
||||
if (fn > 7)
|
||||
return -EINVAL;
|
||||
if (slot > 31)
|
||||
return -EINVAL;
|
||||
if (str[n] != '\0' || fn > 7 || slot > 31) {
|
||||
goto invalid;
|
||||
}
|
||||
*ptr = slot << 3 | fn;
|
||||
return 0;
|
||||
return;
|
||||
|
||||
invalid:
|
||||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
}
|
||||
|
||||
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
|
@ -978,10 +871,9 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
|
|||
PropertyInfo qdev_prop_pci_devfn = {
|
||||
.name = "int32",
|
||||
.legacy_name = "pci-devfn",
|
||||
.parse = parse_pci_devfn,
|
||||
.print = print_pci_devfn,
|
||||
.get = get_int32,
|
||||
.set = set_int32,
|
||||
.set = set_pci_devfn,
|
||||
/* FIXME: this should be -1...255, but the address is stored
|
||||
* into an uint32_t rather than int32_t.
|
||||
*/
|
||||
|
@ -1054,9 +946,9 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
|
|||
|
||||
legacy_name = g_strdup_printf("legacy-%s", name);
|
||||
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
||||
object_property_set_str(OBJECT(dev), value, legacy_name, &err);
|
||||
object_property_parse(OBJECT(dev), value, legacy_name, &err);
|
||||
} else {
|
||||
object_property_set_str(OBJECT(dev), value, name, &err);
|
||||
object_property_parse(OBJECT(dev), value, name, &err);
|
||||
}
|
||||
g_free(legacy_name);
|
||||
|
||||
|
|
|
@ -729,6 +729,30 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
|||
void object_property_set(Object *obj, struct Visitor *v, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_parse:
|
||||
* @obj: the object
|
||||
* @string: the string that will be used to parse the property value.
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Parses a string and writes the result into a property of an object.
|
||||
*/
|
||||
void object_property_parse(Object *obj, const char *string,
|
||||
const char *name, struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_print:
|
||||
* @obj: the object
|
||||
* @name: the name of the property
|
||||
* @errp: returns an error if this function fails
|
||||
*
|
||||
* Returns a string representation of the value of the property. The
|
||||
* caller shall free the string.
|
||||
*/
|
||||
char *object_property_print(Object *obj, const char *name,
|
||||
struct Error **errp);
|
||||
|
||||
/**
|
||||
* object_property_get_type:
|
||||
* @obj: the object
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/qapi-visit-impl.h"
|
||||
|
||||
void visit_start_handle(Visitor *v, void **obj, const char *kind,
|
||||
const char *name, Error **errp)
|
||||
|
@ -116,3 +117,53 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
|
|||
v->type_number(v, obj, name, errp);
|
||||
}
|
||||
}
|
||||
|
||||
void output_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
int i = 0;
|
||||
int value = *obj;
|
||||
char *enum_str;
|
||||
|
||||
assert(strings);
|
||||
while (strings[i++] != NULL);
|
||||
if (value < 0 || value >= i - 1) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
|
||||
return;
|
||||
}
|
||||
|
||||
enum_str = (char *)strings[value];
|
||||
visit_type_str(v, &enum_str, name, errp);
|
||||
}
|
||||
|
||||
void input_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
int64_t value = 0;
|
||||
char *enum_str;
|
||||
|
||||
assert(strings);
|
||||
|
||||
visit_type_str(v, &enum_str, name, errp);
|
||||
if (error_is_set(errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (strings[value] != NULL) {
|
||||
if (strcmp(strings[value], enum_str) == 0) {
|
||||
break;
|
||||
}
|
||||
value++;
|
||||
}
|
||||
|
||||
if (strings[value] == NULL) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
|
||||
g_free(enum_str);
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(enum_str);
|
||||
*obj = value;
|
||||
}
|
||||
|
|
23
qapi/qapi-visit-impl.h
Normal file
23
qapi/qapi-visit-impl.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Core Definitions for QAPI Visitor implementations
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* Author: Paolo Bonizni <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#ifndef QAPI_VISITOR_IMPL_H
|
||||
#define QAPI_VISITOR_IMPL_H
|
||||
|
||||
#include "qapi/qapi-types-core.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
|
||||
void input_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
const char *kind, const char *name, Error **errp);
|
||||
void output_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
const char *kind, const char *name, Error **errp);
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "qmp-input-visitor.h"
|
||||
#include "qapi/qapi-visit-impl.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-objects.h"
|
||||
|
@ -217,37 +218,6 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
|
|||
*obj = qfloat_get_double(qobject_to_qfloat(qobj));
|
||||
}
|
||||
|
||||
static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
int64_t value = 0;
|
||||
char *enum_str;
|
||||
|
||||
assert(strings);
|
||||
|
||||
qmp_input_type_str(v, &enum_str, name, errp);
|
||||
if (error_is_set(errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (strings[value] != NULL) {
|
||||
if (strcmp(strings[value], enum_str) == 0) {
|
||||
break;
|
||||
}
|
||||
value++;
|
||||
}
|
||||
|
||||
if (strings[value] == NULL) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
|
||||
g_free(enum_str);
|
||||
return;
|
||||
}
|
||||
|
||||
g_free(enum_str);
|
||||
*obj = value;
|
||||
}
|
||||
|
||||
static void qmp_input_start_optional(Visitor *v, bool *present,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
|
@ -262,10 +232,6 @@ static void qmp_input_start_optional(Visitor *v, bool *present,
|
|||
*present = true;
|
||||
}
|
||||
|
||||
static void qmp_input_end_optional(Visitor *v, Error **errp)
|
||||
{
|
||||
}
|
||||
|
||||
Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
|
||||
{
|
||||
return &v->visitor;
|
||||
|
@ -288,13 +254,12 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
|
|||
v->visitor.start_list = qmp_input_start_list;
|
||||
v->visitor.next_list = qmp_input_next_list;
|
||||
v->visitor.end_list = qmp_input_end_list;
|
||||
v->visitor.type_enum = qmp_input_type_enum;
|
||||
v->visitor.type_enum = input_type_enum;
|
||||
v->visitor.type_int = qmp_input_type_int;
|
||||
v->visitor.type_bool = qmp_input_type_bool;
|
||||
v->visitor.type_str = qmp_input_type_str;
|
||||
v->visitor.type_number = qmp_input_type_number;
|
||||
v->visitor.start_optional = qmp_input_start_optional;
|
||||
v->visitor.end_optional = qmp_input_end_optional;
|
||||
|
||||
v->obj = obj;
|
||||
qobject_incref(v->obj);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "qmp-output-visitor.h"
|
||||
#include "qapi/qapi-visit-impl.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-objects.h"
|
||||
|
@ -180,25 +181,6 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
|
|||
qmp_output_add(qov, name, qfloat_from_double(*obj));
|
||||
}
|
||||
|
||||
static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[],
|
||||
const char *kind, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
int i = 0;
|
||||
int value = *obj;
|
||||
char *enum_str;
|
||||
|
||||
assert(strings);
|
||||
while (strings[i++] != NULL);
|
||||
if (value < 0 || value >= i - 1) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
|
||||
return;
|
||||
}
|
||||
|
||||
enum_str = (char *)strings[value];
|
||||
qmp_output_type_str(v, &enum_str, name, errp);
|
||||
}
|
||||
|
||||
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
|
||||
{
|
||||
QObject *obj = qmp_output_first(qov);
|
||||
|
@ -239,7 +221,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
|
|||
v->visitor.start_list = qmp_output_start_list;
|
||||
v->visitor.next_list = qmp_output_next_list;
|
||||
v->visitor.end_list = qmp_output_end_list;
|
||||
v->visitor.type_enum = qmp_output_type_enum;
|
||||
v->visitor.type_enum = output_type_enum;
|
||||
v->visitor.type_int = qmp_output_type_int;
|
||||
v->visitor.type_bool = qmp_output_type_bool;
|
||||
v->visitor.type_str = qmp_output_type_str;
|
||||
|
|
138
qapi/string-input-visitor.c
Normal file
138
qapi/string-input-visitor.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* String parsing visitor
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2012
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "string-input-visitor.h"
|
||||
#include "qapi/qapi-visit-impl.h"
|
||||
#include "qerror.h"
|
||||
|
||||
struct StringInputVisitor
|
||||
{
|
||||
Visitor visitor;
|
||||
const char *string;
|
||||
};
|
||||
|
||||
static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
char *endp = (char *) siv->string;
|
||||
long long val;
|
||||
|
||||
errno = 0;
|
||||
if (siv->string) {
|
||||
val = strtoll(siv->string, &endp, 0);
|
||||
}
|
||||
if (!siv->string || errno || endp == siv->string || *endp) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"integer");
|
||||
return;
|
||||
}
|
||||
|
||||
*obj = val;
|
||||
}
|
||||
|
||||
static void parse_type_bool(Visitor *v, bool *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
|
||||
if (siv->string) {
|
||||
if (!strcasecmp(siv->string, "on") ||
|
||||
!strcasecmp(siv->string, "yes") ||
|
||||
!strcasecmp(siv->string, "true")) {
|
||||
*obj = true;
|
||||
return;
|
||||
}
|
||||
if (!strcasecmp(siv->string, "off") ||
|
||||
!strcasecmp(siv->string, "no") ||
|
||||
!strcasecmp(siv->string, "false")) {
|
||||
*obj = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"boolean");
|
||||
}
|
||||
|
||||
static void parse_type_str(Visitor *v, char **obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
if (siv->string) {
|
||||
*obj = g_strdup(siv->string);
|
||||
} else {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"string");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_type_number(Visitor *v, double *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
char *endp = (char *) siv->string;
|
||||
double val;
|
||||
|
||||
errno = 0;
|
||||
if (siv->string) {
|
||||
val = strtod(siv->string, &endp);
|
||||
}
|
||||
if (!siv->string || errno || endp == siv->string || *endp) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"number");
|
||||
return;
|
||||
}
|
||||
|
||||
*obj = val;
|
||||
}
|
||||
|
||||
static void parse_start_optional(Visitor *v, bool *present,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
||||
|
||||
if (!siv->string) {
|
||||
*present = false;
|
||||
return;
|
||||
}
|
||||
|
||||
*present = true;
|
||||
}
|
||||
|
||||
Visitor *string_input_get_visitor(StringInputVisitor *v)
|
||||
{
|
||||
return &v->visitor;
|
||||
}
|
||||
|
||||
void string_input_visitor_cleanup(StringInputVisitor *v)
|
||||
{
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
StringInputVisitor *string_input_visitor_new(const char *str)
|
||||
{
|
||||
StringInputVisitor *v;
|
||||
|
||||
v = g_malloc0(sizeof(*v));
|
||||
|
||||
v->visitor.type_enum = input_type_enum;
|
||||
v->visitor.type_int = parse_type_int;
|
||||
v->visitor.type_bool = parse_type_bool;
|
||||
v->visitor.type_str = parse_type_str;
|
||||
v->visitor.type_number = parse_type_number;
|
||||
v->visitor.start_optional = parse_start_optional;
|
||||
|
||||
v->string = str;
|
||||
return v;
|
||||
}
|
25
qapi/string-input-visitor.h
Normal file
25
qapi/string-input-visitor.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* String parsing Visitor
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2012
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STRING_INPUT_VISITOR_H
|
||||
#define STRING_INPUT_VISITOR_H
|
||||
|
||||
#include "qapi-visit-core.h"
|
||||
|
||||
typedef struct StringInputVisitor StringInputVisitor;
|
||||
|
||||
StringInputVisitor *string_input_visitor_new(const char *str);
|
||||
void string_input_visitor_cleanup(StringInputVisitor *v);
|
||||
|
||||
Visitor *string_input_get_visitor(StringInputVisitor *v);
|
||||
|
||||
#endif
|
89
qapi/string-output-visitor.c
Normal file
89
qapi/string-output-visitor.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* String printing Visitor
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2012
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "string-output-visitor.h"
|
||||
#include "qapi/qapi-visit-impl.h"
|
||||
#include "qerror.h"
|
||||
|
||||
struct StringOutputVisitor
|
||||
{
|
||||
Visitor visitor;
|
||||
char *string;
|
||||
};
|
||||
|
||||
static void string_output_set(StringOutputVisitor *sov, char *string)
|
||||
{
|
||||
g_free(sov->string);
|
||||
sov->string = string;
|
||||
}
|
||||
|
||||
static void print_type_int(Visitor *v, int64_t *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
|
||||
string_output_set(sov, g_strdup_printf("%lld", (long long) *obj));
|
||||
}
|
||||
|
||||
static void print_type_bool(Visitor *v, bool *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
|
||||
string_output_set(sov, g_strdup(*obj ? "true" : "false"));
|
||||
}
|
||||
|
||||
static void print_type_str(Visitor *v, char **obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
|
||||
string_output_set(sov, g_strdup(*obj ? *obj : ""));
|
||||
}
|
||||
|
||||
static void print_type_number(Visitor *v, double *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
|
||||
string_output_set(sov, g_strdup_printf("%g", *obj));
|
||||
}
|
||||
|
||||
char *string_output_get_string(StringOutputVisitor *sov)
|
||||
{
|
||||
char *string = sov->string;
|
||||
sov->string = NULL;
|
||||
return string;
|
||||
}
|
||||
|
||||
Visitor *string_output_get_visitor(StringOutputVisitor *sov)
|
||||
{
|
||||
return &sov->visitor;
|
||||
}
|
||||
|
||||
void string_output_visitor_cleanup(StringOutputVisitor *sov)
|
||||
{
|
||||
g_free(sov->string);
|
||||
g_free(sov);
|
||||
}
|
||||
|
||||
StringOutputVisitor *string_output_visitor_new(void)
|
||||
{
|
||||
StringOutputVisitor *v;
|
||||
|
||||
v = g_malloc0(sizeof(*v));
|
||||
|
||||
v->visitor.type_enum = output_type_enum;
|
||||
v->visitor.type_int = print_type_int;
|
||||
v->visitor.type_bool = print_type_bool;
|
||||
v->visitor.type_str = print_type_str;
|
||||
v->visitor.type_number = print_type_number;
|
||||
|
||||
return v;
|
||||
}
|
26
qapi/string-output-visitor.h
Normal file
26
qapi/string-output-visitor.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* String printing Visitor
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2012
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STRING_OUTPUT_VISITOR_H
|
||||
#define STRING_OUTPUT_VISITOR_H
|
||||
|
||||
#include "qapi-visit-core.h"
|
||||
|
||||
typedef struct StringOutputVisitor StringOutputVisitor;
|
||||
|
||||
StringOutputVisitor *string_output_visitor_new(void);
|
||||
void string_output_visitor_cleanup(StringOutputVisitor *v);
|
||||
|
||||
char *string_output_get_string(StringOutputVisitor *v);
|
||||
Visitor *string_output_get_visitor(StringOutputVisitor *v);
|
||||
|
||||
#endif
|
25
qom/object.c
25
qom/object.c
|
@ -13,6 +13,8 @@
|
|||
#include "qemu/object.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/string-input-visitor.h"
|
||||
#include "qapi/string-output-visitor.h"
|
||||
|
||||
/* TODO: replace QObject with a simpler visitor to avoid a dependency
|
||||
* of the QOM core on QObject? */
|
||||
|
@ -782,6 +784,29 @@ int64_t object_property_get_int(Object *obj, const char *name,
|
|||
return retval;
|
||||
}
|
||||
|
||||
void object_property_parse(Object *obj, const char *string,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
StringInputVisitor *mi;
|
||||
mi = string_input_visitor_new(string);
|
||||
object_property_set(obj, string_input_get_visitor(mi), name, errp);
|
||||
|
||||
string_input_visitor_cleanup(mi);
|
||||
}
|
||||
|
||||
char *object_property_print(Object *obj, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
StringOutputVisitor *mo;
|
||||
char *string;
|
||||
|
||||
mo = string_output_visitor_new();
|
||||
object_property_get(obj, string_output_get_visitor(mo), name, NULL);
|
||||
string = string_output_get_string(mo);
|
||||
string_output_visitor_cleanup(mo);
|
||||
return string;
|
||||
}
|
||||
|
||||
const char *object_property_get_type(Object *obj, const char *name, Error **errp)
|
||||
{
|
||||
ObjectProperty *prop = object_property_find(obj, name);
|
||||
|
|
195
test-string-input-visitor.c
Normal file
195
test-string-input-visitor.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* String Input Visitor unit-tests.
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-input-visitor)
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "qapi/string-input-visitor.h"
|
||||
#include "test-qapi-types.h"
|
||||
#include "test-qapi-visit.h"
|
||||
#include "qemu-objects.h"
|
||||
|
||||
typedef struct TestInputVisitorData {
|
||||
StringInputVisitor *siv;
|
||||
} TestInputVisitorData;
|
||||
|
||||
static void visitor_input_teardown(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
if (data->siv) {
|
||||
string_input_visitor_cleanup(data->siv);
|
||||
data->siv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
Visitor *visitor_input_test_init(TestInputVisitorData *data,
|
||||
const char *string)
|
||||
{
|
||||
Visitor *v;
|
||||
|
||||
data->siv = string_input_visitor_new(string);
|
||||
g_assert(data->siv != NULL);
|
||||
|
||||
v = string_input_get_visitor(data->siv);
|
||||
g_assert(v != NULL);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void test_visitor_in_int(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
int64_t res = 0, value = -42;
|
||||
Error *errp = NULL;
|
||||
Visitor *v;
|
||||
|
||||
v = visitor_input_test_init(data, "-42");
|
||||
|
||||
visit_type_int(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, value);
|
||||
}
|
||||
|
||||
static void test_visitor_in_bool(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
Error *errp = NULL;
|
||||
bool res = false;
|
||||
Visitor *v;
|
||||
|
||||
v = visitor_input_test_init(data, "true");
|
||||
|
||||
visit_type_bool(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, true);
|
||||
visitor_input_teardown(data, unused);
|
||||
|
||||
v = visitor_input_test_init(data, "yes");
|
||||
|
||||
visit_type_bool(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, true);
|
||||
visitor_input_teardown(data, unused);
|
||||
|
||||
v = visitor_input_test_init(data, "on");
|
||||
|
||||
visit_type_bool(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, true);
|
||||
visitor_input_teardown(data, unused);
|
||||
|
||||
v = visitor_input_test_init(data, "false");
|
||||
|
||||
visit_type_bool(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, false);
|
||||
visitor_input_teardown(data, unused);
|
||||
|
||||
v = visitor_input_test_init(data, "no");
|
||||
|
||||
visit_type_bool(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, false);
|
||||
visitor_input_teardown(data, unused);
|
||||
|
||||
v = visitor_input_test_init(data, "off");
|
||||
|
||||
visit_type_bool(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(res, ==, false);
|
||||
}
|
||||
|
||||
static void test_visitor_in_number(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
double res = 0, value = 3.14;
|
||||
Error *errp = NULL;
|
||||
Visitor *v;
|
||||
|
||||
v = visitor_input_test_init(data, "3.14");
|
||||
|
||||
visit_type_number(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpfloat(res, ==, value);
|
||||
}
|
||||
|
||||
static void test_visitor_in_string(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
char *res = NULL, *value = (char *) "Q E M U";
|
||||
Error *errp = NULL;
|
||||
Visitor *v;
|
||||
|
||||
v = visitor_input_test_init(data, value);
|
||||
|
||||
visit_type_str(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpstr(res, ==, value);
|
||||
|
||||
g_free(res);
|
||||
}
|
||||
|
||||
static void test_visitor_in_enum(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
Error *errp = NULL;
|
||||
Visitor *v;
|
||||
EnumOne i;
|
||||
|
||||
for (i = 0; EnumOne_lookup[i]; i++) {
|
||||
EnumOne res = -1;
|
||||
|
||||
v = visitor_input_test_init(data, EnumOne_lookup[i]);
|
||||
|
||||
visit_type_EnumOne(v, &res, NULL, &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
g_assert_cmpint(i, ==, res);
|
||||
|
||||
visitor_input_teardown(data, NULL);
|
||||
}
|
||||
|
||||
data->siv = NULL;
|
||||
}
|
||||
|
||||
static void input_visitor_test_add(const char *testpath,
|
||||
TestInputVisitorData *data,
|
||||
void (*test_func)(TestInputVisitorData *data, const void *user_data))
|
||||
{
|
||||
g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
|
||||
visitor_input_teardown);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TestInputVisitorData in_visitor_data;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
input_visitor_test_add("/string-visitor/input/int",
|
||||
&in_visitor_data, test_visitor_in_int);
|
||||
input_visitor_test_add("/string-visitor/input/bool",
|
||||
&in_visitor_data, test_visitor_in_bool);
|
||||
input_visitor_test_add("/string-visitor/input/number",
|
||||
&in_visitor_data, test_visitor_in_number);
|
||||
input_visitor_test_add("/string-visitor/input/string",
|
||||
&in_visitor_data, test_visitor_in_string);
|
||||
input_visitor_test_add("/string-visitor/input/enum",
|
||||
&in_visitor_data, test_visitor_in_enum);
|
||||
|
||||
g_test_run();
|
||||
|
||||
return 0;
|
||||
}
|
188
test-string-output-visitor.c
Normal file
188
test-string-output-visitor.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* String Output Visitor unit-tests.
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-output-visitor)
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "qapi/string-output-visitor.h"
|
||||
#include "test-qapi-types.h"
|
||||
#include "test-qapi-visit.h"
|
||||
#include "qemu-objects.h"
|
||||
|
||||
typedef struct TestOutputVisitorData {
|
||||
StringOutputVisitor *sov;
|
||||
Visitor *ov;
|
||||
} TestOutputVisitorData;
|
||||
|
||||
static void visitor_output_setup(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
data->sov = string_output_visitor_new();
|
||||
g_assert(data->sov != NULL);
|
||||
|
||||
data->ov = string_output_get_visitor(data->sov);
|
||||
g_assert(data->ov != NULL);
|
||||
}
|
||||
|
||||
static void visitor_output_teardown(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
string_output_visitor_cleanup(data->sov);
|
||||
data->sov = NULL;
|
||||
data->ov = NULL;
|
||||
}
|
||||
|
||||
static void test_visitor_out_int(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
int64_t value = -42;
|
||||
Error *errp = NULL;
|
||||
char *str;
|
||||
|
||||
visit_type_int(data->ov, &value, NULL, &errp);
|
||||
g_assert(error_is_set(&errp) == 0);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
g_assert_cmpstr(str, ==, "-42");
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_bool(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
Error *errp = NULL;
|
||||
bool value = true;
|
||||
char *str;
|
||||
|
||||
visit_type_bool(data->ov, &value, NULL, &errp);
|
||||
g_assert(error_is_set(&errp) == 0);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
g_assert_cmpstr(str, ==, "true");
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_number(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
double value = 3.14;
|
||||
Error *errp = NULL;
|
||||
char *str;
|
||||
|
||||
visit_type_number(data->ov, &value, NULL, &errp);
|
||||
g_assert(error_is_set(&errp) == 0);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
g_assert_cmpstr(str, ==, "3.14");
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_string(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
char *string = (char *) "Q E M U";
|
||||
Error *errp = NULL;
|
||||
char *str;
|
||||
|
||||
visit_type_str(data->ov, &string, NULL, &errp);
|
||||
g_assert(error_is_set(&errp) == 0);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
g_assert_cmpstr(str, ==, string);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_no_string(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
char *string = NULL;
|
||||
Error *errp = NULL;
|
||||
char *str;
|
||||
|
||||
/* A null string should return "" */
|
||||
visit_type_str(data->ov, &string, NULL, &errp);
|
||||
g_assert(error_is_set(&errp) == 0);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
g_assert_cmpstr(str, ==, "");
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_enum(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
Error *errp = NULL;
|
||||
char *str;
|
||||
EnumOne i;
|
||||
|
||||
for (i = 0; i < ENUM_ONE_MAX; i++) {
|
||||
visit_type_EnumOne(data->ov, &i, "unused", &errp);
|
||||
g_assert(!error_is_set(&errp));
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
|
||||
g_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
|
||||
Error *errp;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
|
||||
errp = NULL;
|
||||
visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
|
||||
g_assert(error_is_set(&errp) == true);
|
||||
error_free(errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void output_visitor_test_add(const char *testpath,
|
||||
TestOutputVisitorData *data,
|
||||
void (*test_func)(TestOutputVisitorData *data, const void *user_data))
|
||||
{
|
||||
g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
|
||||
test_func, visitor_output_teardown);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TestOutputVisitorData out_visitor_data;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
output_visitor_test_add("/string-visitor/output/int",
|
||||
&out_visitor_data, test_visitor_out_int);
|
||||
output_visitor_test_add("/string-visitor/output/bool",
|
||||
&out_visitor_data, test_visitor_out_bool);
|
||||
output_visitor_test_add("/string-visitor/output/number",
|
||||
&out_visitor_data, test_visitor_out_number);
|
||||
output_visitor_test_add("/string-visitor/output/string",
|
||||
&out_visitor_data, test_visitor_out_string);
|
||||
output_visitor_test_add("/string-visitor/output/no-string",
|
||||
&out_visitor_data, test_visitor_out_no_string);
|
||||
output_visitor_test_add("/string-visitor/output/enum",
|
||||
&out_visitor_data, test_visitor_out_enum);
|
||||
output_visitor_test_add("/string-visitor/output/enum-errors",
|
||||
&out_visitor_data, test_visitor_out_enum_errors);
|
||||
|
||||
g_test_run();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
|
||||
CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
|
||||
CHECKS += test-coroutine
|
||||
CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
|
||||
|
||||
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
|
||||
|
||||
|
@ -12,7 +12,9 @@ check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
|
|||
check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
|
||||
test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
|
||||
|
||||
test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
|
||||
test-qmp-input-visitor.o test-qmp-output-visitor.o \
|
||||
test-string-input-visitor.o test-string-output-visitor.o \
|
||||
test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
|
||||
|
||||
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
|
||||
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
|
@ -25,6 +27,12 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
|
|||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
|
||||
|
||||
test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
|
||||
test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
|
||||
|
||||
test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
|
||||
test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
|
||||
|
||||
test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
|
||||
test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
|
||||
|
||||
|
|
Loading…
Reference in a new issue