|  | /* | 
|  | * 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 "qemu-common.h" | 
|  | #include "qapi/string-input-visitor.h" | 
|  | #include "test-qapi-types.h" | 
|  | #include "test-qapi-visit.h" | 
|  | #include "qapi/qmp/types.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; | 
|  | } | 
|  |  | 
|  | /* Try to crash the visitors */ | 
|  | static void test_visitor_in_fuzz(TestInputVisitorData *data, | 
|  | const void *unused) | 
|  | { | 
|  | int64_t ires; | 
|  | bool bres; | 
|  | double nres; | 
|  | char *sres; | 
|  | EnumOne eres; | 
|  | Visitor *v; | 
|  | unsigned int i; | 
|  | char buf[10000]; | 
|  |  | 
|  | for (i = 0; i < 100; i++) { | 
|  | unsigned int j; | 
|  |  | 
|  | j = g_test_rand_int_range(0, sizeof(buf) - 1); | 
|  |  | 
|  | buf[j] = '\0'; | 
|  |  | 
|  | if (j != 0) { | 
|  | for (j--; j != 0; j--) { | 
|  | buf[j - 1] = (char)g_test_rand_int_range(0, 256); | 
|  | } | 
|  | } | 
|  |  | 
|  | v = visitor_input_test_init(data, buf); | 
|  | visit_type_int(v, &ires, NULL, NULL); | 
|  |  | 
|  | v = visitor_input_test_init(data, buf); | 
|  | visit_type_bool(v, &bres, NULL, NULL); | 
|  | visitor_input_teardown(data, NULL); | 
|  |  | 
|  | v = visitor_input_test_init(data, buf); | 
|  | visit_type_number(v, &nres, NULL, NULL); | 
|  |  | 
|  | v = visitor_input_test_init(data, buf); | 
|  | sres = NULL; | 
|  | visit_type_str(v, &sres, NULL, NULL); | 
|  | g_free(sres); | 
|  |  | 
|  | v = visitor_input_test_init(data, buf); | 
|  | visit_type_EnumOne(v, &eres, NULL, NULL); | 
|  | visitor_input_teardown(data, 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); | 
|  | input_visitor_test_add("/string-visitor/input/fuzz", | 
|  | &in_visitor_data, test_visitor_in_fuzz); | 
|  |  | 
|  | g_test_run(); | 
|  |  | 
|  | return 0; | 
|  | } |