1 /* 2 * QAPI Forwarding Visitor unit-tests. 3 * 4 * Copyright (C) 2021 Red Hat Inc. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 12 #include "qemu-common.h" 13 #include "qapi/forward-visitor.h" 14 #include "qapi/qobject-input-visitor.h" 15 #include "qapi/error.h" 16 #include "qapi/qmp/qobject.h" 17 #include "qapi/qmp/qdict.h" 18 #include "test-qapi-visit.h" 19 #include "qemu/option.h" 20 21 typedef bool GenericVisitor (Visitor *, const char *, void **, Error **); 22 #define CAST_VISIT_TYPE(fn) ((GenericVisitor *)(fn)) 23 24 /* 25 * Parse @srcstr and wrap it with a ForwardFieldVisitor converting "src" to 26 * "dst". Check that visiting the result with "src" name fails, and return 27 * the result of visiting "dst". 28 */ 29 static void *visit_with_forward(const char *srcstr, GenericVisitor *fn) 30 { 31 bool help = false; 32 QDict *src = keyval_parse(srcstr, NULL, &help, &error_abort); 33 Visitor *v, *alias_v; 34 Error *err = NULL; 35 void *result = NULL; 36 37 v = qobject_input_visitor_new_keyval(QOBJECT(src)); 38 visit_start_struct(v, NULL, NULL, 0, &error_abort); 39 40 alias_v = visitor_forward_field(v, "dst", "src"); 41 fn(alias_v, "src", &result, &err); 42 error_free_or_abort(&err); 43 assert(!result); 44 fn(alias_v, "dst", &result, &err); 45 assert(err == NULL); 46 visit_free(alias_v); 47 48 visit_end_struct(v, NULL); 49 visit_free(v); 50 qobject_unref(QOBJECT(src)); 51 return result; 52 } 53 54 static void test_forward_any(void) 55 { 56 QObject *src = visit_with_forward("src.integer=42,src.string=Hello,src.enum1=value2", 57 CAST_VISIT_TYPE(visit_type_any)); 58 Visitor *v = qobject_input_visitor_new_keyval(src); 59 Error *err = NULL; 60 UserDefOne *dst; 61 62 visit_type_UserDefOne(v, NULL, &dst, &err); 63 assert(err == NULL); 64 visit_free(v); 65 66 g_assert_cmpint(dst->integer, ==, 42); 67 g_assert_cmpstr(dst->string, ==, "Hello"); 68 g_assert_cmpint(dst->has_enum1, ==, true); 69 g_assert_cmpint(dst->enum1, ==, ENUM_ONE_VALUE2); 70 qapi_free_UserDefOne(dst); 71 qobject_unref(QOBJECT(src)); 72 } 73 74 static void test_forward_size(void) 75 { 76 /* 77 * visit_type_size does not return a pointer, so visit_with_forward 78 * cannot be used. 79 */ 80 bool help = false; 81 QDict *src = keyval_parse("src=1.5M", NULL, &help, &error_abort); 82 Visitor *v, *alias_v; 83 Error *err = NULL; 84 uint64_t result = 0; 85 86 v = qobject_input_visitor_new_keyval(QOBJECT(src)); 87 visit_start_struct(v, NULL, NULL, 0, &error_abort); 88 89 alias_v = visitor_forward_field(v, "dst", "src"); 90 visit_type_size(alias_v, "src", &result, &err); 91 error_free_or_abort(&err); 92 visit_type_size(alias_v, "dst", &result, &err); 93 assert(result == 3 << 19); 94 assert(err == NULL); 95 visit_free(alias_v); 96 97 visit_end_struct(v, NULL); 98 visit_free(v); 99 qobject_unref(QOBJECT(src)); 100 } 101 102 static void test_forward_number(void) 103 { 104 /* 105 * visit_type_number does not return a pointer, so visit_with_forward 106 * cannot be used. 107 */ 108 bool help = false; 109 QDict *src = keyval_parse("src=1.5", NULL, &help, &error_abort); 110 Visitor *v, *alias_v; 111 Error *err = NULL; 112 double result = 0.0; 113 114 v = qobject_input_visitor_new_keyval(QOBJECT(src)); 115 visit_start_struct(v, NULL, NULL, 0, &error_abort); 116 117 alias_v = visitor_forward_field(v, "dst", "src"); 118 visit_type_number(alias_v, "src", &result, &err); 119 error_free_or_abort(&err); 120 visit_type_number(alias_v, "dst", &result, &err); 121 assert(result == 1.5); 122 assert(err == NULL); 123 visit_free(alias_v); 124 125 visit_end_struct(v, NULL); 126 visit_free(v); 127 qobject_unref(QOBJECT(src)); 128 } 129 130 static void test_forward_string(void) 131 { 132 char *dst = visit_with_forward("src=Hello", 133 CAST_VISIT_TYPE(visit_type_str)); 134 135 g_assert_cmpstr(dst, ==, "Hello"); 136 g_free(dst); 137 } 138 139 static void test_forward_struct(void) 140 { 141 UserDefOne *dst = visit_with_forward("src.integer=42,src.string=Hello", 142 CAST_VISIT_TYPE(visit_type_UserDefOne)); 143 144 g_assert_cmpint(dst->integer, ==, 42); 145 g_assert_cmpstr(dst->string, ==, "Hello"); 146 g_assert_cmpint(dst->has_enum1, ==, false); 147 qapi_free_UserDefOne(dst); 148 } 149 150 static void test_forward_alternate(void) 151 { 152 AltStrObj *s_dst = visit_with_forward("src=hello", 153 CAST_VISIT_TYPE(visit_type_AltStrObj)); 154 AltStrObj *o_dst = visit_with_forward("src.integer=42,src.boolean=true,src.string=world", 155 CAST_VISIT_TYPE(visit_type_AltStrObj)); 156 157 g_assert_cmpint(s_dst->type, ==, QTYPE_QSTRING); 158 g_assert_cmpstr(s_dst->u.s, ==, "hello"); 159 g_assert_cmpint(o_dst->type, ==, QTYPE_QDICT); 160 g_assert_cmpint(o_dst->u.o.integer, ==, 42); 161 g_assert_cmpint(o_dst->u.o.boolean, ==, true); 162 g_assert_cmpstr(o_dst->u.o.string, ==, "world"); 163 164 qapi_free_AltStrObj(s_dst); 165 qapi_free_AltStrObj(o_dst); 166 } 167 168 static void test_forward_list(void) 169 { 170 uint8List *dst = visit_with_forward("src.0=1,src.1=2,src.2=3,src.3=4", 171 CAST_VISIT_TYPE(visit_type_uint8List)); 172 uint8List *tmp; 173 int i; 174 175 for (tmp = dst, i = 1; i <= 4; i++) { 176 g_assert(tmp); 177 g_assert_cmpint(tmp->value, ==, i); 178 tmp = tmp->next; 179 } 180 g_assert(!tmp); 181 qapi_free_uint8List(dst); 182 } 183 184 int main(int argc, char **argv) 185 { 186 g_test_init(&argc, &argv, NULL); 187 188 g_test_add_func("/visitor/forward/struct", test_forward_struct); 189 g_test_add_func("/visitor/forward/alternate", test_forward_alternate); 190 g_test_add_func("/visitor/forward/string", test_forward_string); 191 g_test_add_func("/visitor/forward/size", test_forward_size); 192 g_test_add_func("/visitor/forward/number", test_forward_number); 193 g_test_add_func("/visitor/forward/any", test_forward_any); 194 g_test_add_func("/visitor/forward/list", test_forward_list); 195 196 return g_test_run(); 197 } 198