Do not require the whole option machinery to handle keyval, as it is used by QAPI alone, without the option API. And match the associated unit name. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-Id: <20220420132624.2439741-24-marcandre.lureau@redhat.com>
		
			
				
	
	
		
			197 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * QAPI Forwarding Visitor unit-tests.
 | 
						|
 *
 | 
						|
 * Copyright (C) 2021 Red Hat Inc.
 | 
						|
 *
 | 
						|
 * 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 "qemu/osdep.h"
 | 
						|
 | 
						|
#include "qapi/forward-visitor.h"
 | 
						|
#include "qapi/qobject-input-visitor.h"
 | 
						|
#include "qapi/error.h"
 | 
						|
#include "qapi/qmp/qobject.h"
 | 
						|
#include "qapi/qmp/qdict.h"
 | 
						|
#include "test-qapi-visit.h"
 | 
						|
#include "qemu/keyval.h"
 | 
						|
 | 
						|
typedef bool GenericVisitor (Visitor *, const char *, void **, Error **);
 | 
						|
#define CAST_VISIT_TYPE(fn) ((GenericVisitor *)(fn))
 | 
						|
 | 
						|
/*
 | 
						|
 * Parse @srcstr and wrap it with a ForwardFieldVisitor converting "src" to
 | 
						|
 * "dst". Check that visiting the result with "src" name fails, and return
 | 
						|
 * the result of visiting "dst".
 | 
						|
 */
 | 
						|
static void *visit_with_forward(const char *srcstr, GenericVisitor *fn)
 | 
						|
{
 | 
						|
    bool help = false;
 | 
						|
    QDict *src = keyval_parse(srcstr, NULL, &help, &error_abort);
 | 
						|
    Visitor *v, *alias_v;
 | 
						|
    Error *err = NULL;
 | 
						|
    void *result = NULL;
 | 
						|
 | 
						|
    v = qobject_input_visitor_new_keyval(QOBJECT(src));
 | 
						|
    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 | 
						|
 | 
						|
    alias_v = visitor_forward_field(v, "dst", "src");
 | 
						|
    fn(alias_v, "src", &result, &err);
 | 
						|
    error_free_or_abort(&err);
 | 
						|
    assert(!result);
 | 
						|
    fn(alias_v, "dst", &result, &err);
 | 
						|
    assert(err == NULL);
 | 
						|
    visit_free(alias_v);
 | 
						|
 | 
						|
    visit_end_struct(v, NULL);
 | 
						|
    visit_free(v);
 | 
						|
    qobject_unref(QOBJECT(src));
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_any(void)
 | 
						|
{
 | 
						|
    QObject *src = visit_with_forward("src.integer=42,src.string=Hello,src.enum1=value2",
 | 
						|
                                      CAST_VISIT_TYPE(visit_type_any));
 | 
						|
    Visitor *v = qobject_input_visitor_new_keyval(src);
 | 
						|
    Error *err = NULL;
 | 
						|
    UserDefOne *dst;
 | 
						|
 | 
						|
    visit_type_UserDefOne(v, NULL, &dst, &err);
 | 
						|
    assert(err == NULL);
 | 
						|
    visit_free(v);
 | 
						|
 | 
						|
    g_assert_cmpint(dst->integer, ==, 42);
 | 
						|
    g_assert_cmpstr(dst->string, ==, "Hello");
 | 
						|
    g_assert_cmpint(dst->has_enum1, ==, true);
 | 
						|
    g_assert_cmpint(dst->enum1, ==, ENUM_ONE_VALUE2);
 | 
						|
    qapi_free_UserDefOne(dst);
 | 
						|
    qobject_unref(QOBJECT(src));
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_size(void)
 | 
						|
{
 | 
						|
    /*
 | 
						|
     * visit_type_size does not return a pointer, so visit_with_forward
 | 
						|
     * cannot be used.
 | 
						|
     */
 | 
						|
    bool help = false;
 | 
						|
    QDict *src = keyval_parse("src=1.5M", NULL, &help, &error_abort);
 | 
						|
    Visitor *v, *alias_v;
 | 
						|
    Error *err = NULL;
 | 
						|
    uint64_t result = 0;
 | 
						|
 | 
						|
    v = qobject_input_visitor_new_keyval(QOBJECT(src));
 | 
						|
    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 | 
						|
 | 
						|
    alias_v = visitor_forward_field(v, "dst", "src");
 | 
						|
    visit_type_size(alias_v, "src", &result, &err);
 | 
						|
    error_free_or_abort(&err);
 | 
						|
    visit_type_size(alias_v, "dst", &result, &err);
 | 
						|
    assert(result == 3 << 19);
 | 
						|
    assert(err == NULL);
 | 
						|
    visit_free(alias_v);
 | 
						|
 | 
						|
    visit_end_struct(v, NULL);
 | 
						|
    visit_free(v);
 | 
						|
    qobject_unref(QOBJECT(src));
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_number(void)
 | 
						|
{
 | 
						|
    /*
 | 
						|
     * visit_type_number does not return a pointer, so visit_with_forward
 | 
						|
     * cannot be used.
 | 
						|
     */
 | 
						|
    bool help = false;
 | 
						|
    QDict *src = keyval_parse("src=1.5", NULL, &help, &error_abort);
 | 
						|
    Visitor *v, *alias_v;
 | 
						|
    Error *err = NULL;
 | 
						|
    double result = 0.0;
 | 
						|
 | 
						|
    v = qobject_input_visitor_new_keyval(QOBJECT(src));
 | 
						|
    visit_start_struct(v, NULL, NULL, 0, &error_abort);
 | 
						|
 | 
						|
    alias_v = visitor_forward_field(v, "dst", "src");
 | 
						|
    visit_type_number(alias_v, "src", &result, &err);
 | 
						|
    error_free_or_abort(&err);
 | 
						|
    visit_type_number(alias_v, "dst", &result, &err);
 | 
						|
    assert(result == 1.5);
 | 
						|
    assert(err == NULL);
 | 
						|
    visit_free(alias_v);
 | 
						|
 | 
						|
    visit_end_struct(v, NULL);
 | 
						|
    visit_free(v);
 | 
						|
    qobject_unref(QOBJECT(src));
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_string(void)
 | 
						|
{
 | 
						|
    char *dst = visit_with_forward("src=Hello",
 | 
						|
                                   CAST_VISIT_TYPE(visit_type_str));
 | 
						|
 | 
						|
    g_assert_cmpstr(dst, ==, "Hello");
 | 
						|
    g_free(dst);
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_struct(void)
 | 
						|
{
 | 
						|
    UserDefOne *dst = visit_with_forward("src.integer=42,src.string=Hello",
 | 
						|
                                         CAST_VISIT_TYPE(visit_type_UserDefOne));
 | 
						|
 | 
						|
    g_assert_cmpint(dst->integer, ==, 42);
 | 
						|
    g_assert_cmpstr(dst->string, ==, "Hello");
 | 
						|
    g_assert_cmpint(dst->has_enum1, ==, false);
 | 
						|
    qapi_free_UserDefOne(dst);
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_alternate(void)
 | 
						|
{
 | 
						|
    AltStrObj *s_dst = visit_with_forward("src=hello",
 | 
						|
                                          CAST_VISIT_TYPE(visit_type_AltStrObj));
 | 
						|
    AltStrObj *o_dst = visit_with_forward("src.integer=42,src.boolean=true,src.string=world",
 | 
						|
                                          CAST_VISIT_TYPE(visit_type_AltStrObj));
 | 
						|
 | 
						|
    g_assert_cmpint(s_dst->type, ==, QTYPE_QSTRING);
 | 
						|
    g_assert_cmpstr(s_dst->u.s, ==, "hello");
 | 
						|
    g_assert_cmpint(o_dst->type, ==, QTYPE_QDICT);
 | 
						|
    g_assert_cmpint(o_dst->u.o.integer, ==, 42);
 | 
						|
    g_assert_cmpint(o_dst->u.o.boolean, ==, true);
 | 
						|
    g_assert_cmpstr(o_dst->u.o.string, ==, "world");
 | 
						|
 | 
						|
    qapi_free_AltStrObj(s_dst);
 | 
						|
    qapi_free_AltStrObj(o_dst);
 | 
						|
}
 | 
						|
 | 
						|
static void test_forward_list(void)
 | 
						|
{
 | 
						|
    uint8List *dst = visit_with_forward("src.0=1,src.1=2,src.2=3,src.3=4",
 | 
						|
                                        CAST_VISIT_TYPE(visit_type_uint8List));
 | 
						|
    uint8List *tmp;
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (tmp = dst, i = 1; i <= 4; i++) {
 | 
						|
        g_assert(tmp);
 | 
						|
        g_assert_cmpint(tmp->value, ==, i);
 | 
						|
        tmp = tmp->next;
 | 
						|
    }
 | 
						|
    g_assert(!tmp);
 | 
						|
    qapi_free_uint8List(dst);
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char **argv)
 | 
						|
{
 | 
						|
    g_test_init(&argc, &argv, NULL);
 | 
						|
 | 
						|
    g_test_add_func("/visitor/forward/struct", test_forward_struct);
 | 
						|
    g_test_add_func("/visitor/forward/alternate", test_forward_alternate);
 | 
						|
    g_test_add_func("/visitor/forward/string", test_forward_string);
 | 
						|
    g_test_add_func("/visitor/forward/size", test_forward_size);
 | 
						|
    g_test_add_func("/visitor/forward/number", test_forward_number);
 | 
						|
    g_test_add_func("/visitor/forward/any", test_forward_any);
 | 
						|
    g_test_add_func("/visitor/forward/list", test_forward_list);
 | 
						|
 | 
						|
    return g_test_run();
 | 
						|
}
 |