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