Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 1 | /* |
| 2 | * QMP Input Visitor unit-tests (strict mode). |
| 3 | * |
| 4 | * Copyright (C) 2011-2012 Red Hat Inc. |
| 5 | * |
| 6 | * Authors: |
| 7 | * Luiz Capitulino <lcapitulino@redhat.com> |
| 8 | * Paolo Bonzini <pbonzini@redhat.com> |
| 9 | * |
| 10 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 11 | * See the COPYING file in the top-level directory. |
| 12 | */ |
| 13 | |
| 14 | #include <glib.h> |
| 15 | #include <stdarg.h> |
| 16 | |
Paolo Bonzini | 79ee7df | 2012-12-06 11:22:34 +0100 | [diff] [blame] | 17 | #include "qemu-common.h" |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 18 | #include "qapi/qmp-input-visitor.h" |
| 19 | #include "test-qapi-types.h" |
| 20 | #include "test-qapi-visit.h" |
Paolo Bonzini | 7b1b5d1 | 2012-12-17 18:19:43 +0100 | [diff] [blame] | 21 | #include "qapi/qmp/types.h" |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 22 | |
| 23 | typedef struct TestInputVisitorData { |
| 24 | QObject *obj; |
| 25 | QmpInputVisitor *qiv; |
| 26 | } TestInputVisitorData; |
| 27 | |
| 28 | static void validate_teardown(TestInputVisitorData *data, |
| 29 | const void *unused) |
| 30 | { |
| 31 | qobject_decref(data->obj); |
| 32 | data->obj = NULL; |
| 33 | |
| 34 | if (data->qiv) { |
| 35 | qmp_input_visitor_cleanup(data->qiv); |
| 36 | data->qiv = NULL; |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | /* This is provided instead of a test setup function so that the JSON |
| 41 | string used by the tests are kept in the test functions (and not |
| 42 | int main()) */ |
| 43 | static GCC_FMT_ATTR(2, 3) |
| 44 | Visitor *validate_test_init(TestInputVisitorData *data, |
| 45 | const char *json_string, ...) |
| 46 | { |
| 47 | Visitor *v; |
| 48 | va_list ap; |
| 49 | |
| 50 | va_start(ap, json_string); |
| 51 | data->obj = qobject_from_jsonv(json_string, &ap); |
| 52 | va_end(ap); |
| 53 | |
| 54 | g_assert(data->obj != NULL); |
| 55 | |
| 56 | data->qiv = qmp_input_visitor_new_strict(data->obj); |
| 57 | g_assert(data->qiv != NULL); |
| 58 | |
| 59 | v = qmp_input_get_visitor(data->qiv); |
| 60 | g_assert(v != NULL); |
| 61 | |
| 62 | return v; |
| 63 | } |
| 64 | |
| 65 | typedef struct TestStruct |
| 66 | { |
| 67 | int64_t integer; |
| 68 | bool boolean; |
| 69 | char *string; |
| 70 | } TestStruct; |
| 71 | |
| 72 | static void visit_type_TestStruct(Visitor *v, TestStruct **obj, |
| 73 | const char *name, Error **errp) |
| 74 | { |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 75 | Error *err = NULL; |
| 76 | |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 77 | visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 78 | &err); |
| 79 | if (err) { |
| 80 | goto out; |
| 81 | } |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 82 | |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 83 | visit_type_int(v, &(*obj)->integer, "integer", &err); |
Markus Armbruster | 297a364 | 2014-05-07 09:53:54 +0200 | [diff] [blame] | 84 | if (err) { |
| 85 | goto out_end; |
| 86 | } |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 87 | visit_type_bool(v, &(*obj)->boolean, "boolean", &err); |
Markus Armbruster | 297a364 | 2014-05-07 09:53:54 +0200 | [diff] [blame] | 88 | if (err) { |
| 89 | goto out_end; |
| 90 | } |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 91 | visit_type_str(v, &(*obj)->string, "string", &err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 92 | |
Markus Armbruster | 297a364 | 2014-05-07 09:53:54 +0200 | [diff] [blame] | 93 | out_end: |
| 94 | error_propagate(errp, err); |
| 95 | err = NULL; |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 96 | visit_end_struct(v, &err); |
Markus Armbruster | cdaec38 | 2014-05-07 09:53:53 +0200 | [diff] [blame] | 97 | out: |
| 98 | error_propagate(errp, err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | static void test_validate_struct(TestInputVisitorData *data, |
| 102 | const void *unused) |
| 103 | { |
| 104 | TestStruct *p = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 105 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 106 | Visitor *v; |
| 107 | |
| 108 | v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); |
| 109 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 110 | visit_type_TestStruct(v, &p, NULL, &err); |
| 111 | g_assert(!err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 112 | g_free(p->string); |
| 113 | g_free(p); |
| 114 | } |
| 115 | |
| 116 | static void test_validate_struct_nested(TestInputVisitorData *data, |
| 117 | const void *unused) |
| 118 | { |
| 119 | UserDefNested *udp = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 120 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 121 | Visitor *v; |
| 122 | |
| 123 | v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}"); |
| 124 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 125 | visit_type_UserDefNested(v, &udp, NULL, &err); |
| 126 | g_assert(!err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 127 | qapi_free_UserDefNested(udp); |
| 128 | } |
| 129 | |
| 130 | static void test_validate_list(TestInputVisitorData *data, |
| 131 | const void *unused) |
| 132 | { |
| 133 | UserDefOneList *head = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 134 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 135 | Visitor *v; |
| 136 | |
| 137 | v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); |
| 138 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 139 | visit_type_UserDefOneList(v, &head, NULL, &err); |
| 140 | g_assert(!err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 141 | qapi_free_UserDefOneList(head); |
| 142 | } |
| 143 | |
| 144 | static void test_validate_union(TestInputVisitorData *data, |
| 145 | const void *unused) |
| 146 | { |
| 147 | UserDefUnion *tmp = NULL; |
| 148 | Visitor *v; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 149 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 150 | |
Markus Armbruster | 7ad993b | 2014-03-01 08:40:32 +0100 | [diff] [blame] | 151 | v = validate_test_init(data, "{ 'type': 'b', 'integer': 41, 'data' : { 'integer': 42 } }"); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 152 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 153 | visit_type_UserDefUnion(v, &tmp, NULL, &err); |
| 154 | g_assert(!err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 155 | qapi_free_UserDefUnion(tmp); |
| 156 | } |
| 157 | |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 158 | static void test_validate_union_flat(TestInputVisitorData *data, |
| 159 | const void *unused) |
| 160 | { |
| 161 | UserDefFlatUnion *tmp = NULL; |
| 162 | Visitor *v; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 163 | Error *err = NULL; |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 164 | |
Wenchao Xia | 5223070 | 2014-03-04 18:44:39 -0800 | [diff] [blame] | 165 | v = validate_test_init(data, |
| 166 | "{ 'enum1': 'value1', " |
| 167 | "'string': 'str', " |
| 168 | "'boolean': true }"); |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 169 | /* TODO when generator bug is fixed, add 'integer': 41 */ |
| 170 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 171 | visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); |
| 172 | g_assert(!err); |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 173 | qapi_free_UserDefFlatUnion(tmp); |
| 174 | } |
| 175 | |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 176 | static void test_validate_union_anon(TestInputVisitorData *data, |
| 177 | const void *unused) |
| 178 | { |
| 179 | UserDefAnonUnion *tmp = NULL; |
| 180 | Visitor *v; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 181 | Error *err = NULL; |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 182 | |
| 183 | v = validate_test_init(data, "42"); |
| 184 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 185 | visit_type_UserDefAnonUnion(v, &tmp, NULL, &err); |
| 186 | g_assert(!err); |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 187 | qapi_free_UserDefAnonUnion(tmp); |
| 188 | } |
| 189 | |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 190 | static void test_validate_fail_struct(TestInputVisitorData *data, |
| 191 | const void *unused) |
| 192 | { |
| 193 | TestStruct *p = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 194 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 195 | Visitor *v; |
| 196 | |
| 197 | v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }"); |
| 198 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 199 | visit_type_TestStruct(v, &p, NULL, &err); |
| 200 | g_assert(err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 201 | if (p) { |
| 202 | g_free(p->string); |
| 203 | } |
| 204 | g_free(p); |
| 205 | } |
| 206 | |
| 207 | static void test_validate_fail_struct_nested(TestInputVisitorData *data, |
| 208 | const void *unused) |
| 209 | { |
| 210 | UserDefNested *udp = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 211 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 212 | Visitor *v; |
| 213 | |
| 214 | v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}"); |
| 215 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 216 | visit_type_UserDefNested(v, &udp, NULL, &err); |
| 217 | g_assert(err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 218 | qapi_free_UserDefNested(udp); |
| 219 | } |
| 220 | |
| 221 | static void test_validate_fail_list(TestInputVisitorData *data, |
| 222 | const void *unused) |
| 223 | { |
| 224 | UserDefOneList *head = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 225 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 226 | Visitor *v; |
| 227 | |
| 228 | v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]"); |
| 229 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 230 | visit_type_UserDefOneList(v, &head, NULL, &err); |
| 231 | g_assert(err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 232 | qapi_free_UserDefOneList(head); |
| 233 | } |
| 234 | |
| 235 | static void test_validate_fail_union(TestInputVisitorData *data, |
| 236 | const void *unused) |
| 237 | { |
| 238 | UserDefUnion *tmp = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 239 | Error *err = NULL; |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 240 | Visitor *v; |
| 241 | |
Markus Armbruster | 7ad993b | 2014-03-01 08:40:32 +0100 | [diff] [blame] | 242 | v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }"); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 243 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 244 | visit_type_UserDefUnion(v, &tmp, NULL, &err); |
| 245 | g_assert(err); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 246 | qapi_free_UserDefUnion(tmp); |
| 247 | } |
| 248 | |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 249 | static void test_validate_fail_union_flat(TestInputVisitorData *data, |
| 250 | const void *unused) |
| 251 | { |
| 252 | UserDefFlatUnion *tmp = NULL; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 253 | Error *err = NULL; |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 254 | Visitor *v; |
| 255 | |
| 256 | v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }"); |
| 257 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 258 | visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); |
| 259 | g_assert(err); |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 260 | qapi_free_UserDefFlatUnion(tmp); |
| 261 | } |
| 262 | |
Michael Roth | cb55111 | 2014-09-18 15:36:42 -0500 | [diff] [blame] | 263 | static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data, |
| 264 | const void *unused) |
| 265 | { |
| 266 | UserDefFlatUnion2 *tmp = NULL; |
| 267 | Error *err = NULL; |
| 268 | Visitor *v; |
| 269 | |
| 270 | /* test situation where discriminator field ('enum1' here) is missing */ |
| 271 | v = validate_test_init(data, "{ 'string': 'c', 'string1': 'd', 'string2': 'e' }"); |
| 272 | |
| 273 | visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err); |
| 274 | g_assert(err); |
| 275 | qapi_free_UserDefFlatUnion2(tmp); |
| 276 | } |
| 277 | |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 278 | static void test_validate_fail_union_anon(TestInputVisitorData *data, |
| 279 | const void *unused) |
| 280 | { |
| 281 | UserDefAnonUnion *tmp = NULL; |
| 282 | Visitor *v; |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 283 | Error *err = NULL; |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 284 | |
| 285 | v = validate_test_init(data, "3.14"); |
| 286 | |
Markus Armbruster | e940f54 | 2014-05-02 13:26:29 +0200 | [diff] [blame] | 287 | visit_type_UserDefAnonUnion(v, &tmp, NULL, &err); |
| 288 | g_assert(err); |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 289 | qapi_free_UserDefAnonUnion(tmp); |
| 290 | } |
| 291 | |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 292 | static void validate_test_add(const char *testpath, |
| 293 | TestInputVisitorData *data, |
| 294 | void (*test_func)(TestInputVisitorData *data, const void *user_data)) |
| 295 | { |
| 296 | g_test_add(testpath, TestInputVisitorData, data, NULL, test_func, |
| 297 | validate_teardown); |
| 298 | } |
| 299 | |
| 300 | int main(int argc, char **argv) |
| 301 | { |
| 302 | TestInputVisitorData testdata; |
| 303 | |
| 304 | g_test_init(&argc, &argv, NULL); |
| 305 | |
| 306 | validate_test_add("/visitor/input-strict/pass/struct", |
| 307 | &testdata, test_validate_struct); |
| 308 | validate_test_add("/visitor/input-strict/pass/struct-nested", |
| 309 | &testdata, test_validate_struct_nested); |
| 310 | validate_test_add("/visitor/input-strict/pass/list", |
| 311 | &testdata, test_validate_list); |
| 312 | validate_test_add("/visitor/input-strict/pass/union", |
| 313 | &testdata, test_validate_union); |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 314 | validate_test_add("/visitor/input-strict/pass/union-flat", |
| 315 | &testdata, test_validate_union_flat); |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 316 | validate_test_add("/visitor/input-strict/pass/union-anon", |
| 317 | &testdata, test_validate_union_anon); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 318 | validate_test_add("/visitor/input-strict/fail/struct", |
| 319 | &testdata, test_validate_fail_struct); |
| 320 | validate_test_add("/visitor/input-strict/fail/struct-nested", |
| 321 | &testdata, test_validate_fail_struct_nested); |
| 322 | validate_test_add("/visitor/input-strict/fail/list", |
| 323 | &testdata, test_validate_fail_list); |
| 324 | validate_test_add("/visitor/input-strict/fail/union", |
| 325 | &testdata, test_validate_fail_union); |
Markus Armbruster | 2fc0043 | 2014-03-01 08:40:33 +0100 | [diff] [blame] | 326 | validate_test_add("/visitor/input-strict/fail/union-flat", |
| 327 | &testdata, test_validate_fail_union_flat); |
Michael Roth | cb55111 | 2014-09-18 15:36:42 -0500 | [diff] [blame] | 328 | validate_test_add("/visitor/input-strict/fail/union-flat-no-discriminator", |
| 329 | &testdata, test_validate_fail_union_flat_no_discrim); |
Markus Armbruster | 2c38b60 | 2014-03-01 08:40:30 +0100 | [diff] [blame] | 330 | validate_test_add("/visitor/input-strict/fail/union-anon", |
| 331 | &testdata, test_validate_fail_union_anon); |
Paolo Bonzini | e38ac96 | 2012-03-22 12:51:10 +0100 | [diff] [blame] | 332 | |
| 333 | g_test_run(); |
| 334 | |
| 335 | return 0; |
| 336 | } |