test makefile overhaul

This introduces new test reporting infrastructure based on
gtester and gtester-report.

Also, all existing tests are moved to tests/, and tests/Makefile
is reorganized to factor out the commonalities in the rules.

Signed-off-by: Anthony Liguori <aliguori@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Paolo Bonzini 2012-03-28 15:42:01 +02:00 committed by Anthony Liguori
parent 040b66f3f9
commit b93b63f574
16 changed files with 119 additions and 41 deletions

View file

@ -1,61 +1,113 @@
export SRC_PATH
CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
CHECKS += test-qmp-commands
CHECKS += $(SRC_PATH)/tests/qemu-iotests-quick.sh
check-unit-y = tests/check-qdict$(EXESUF)
check-unit-y += tests/check-qfloat$(EXESUF)
check-unit-y += tests/check-qint$(EXESUF)
check-unit-y += tests/check-qstring$(EXESUF)
check-unit-y += tests/check-qlist$(EXESUF)
check-unit-y += tests/check-qjson$(EXESUF)
check-unit-y += tests/test-qmp-output-visitor$(EXESUF)
check-unit-y += tests/test-qmp-input-visitor$(EXESUF)
check-unit-y += tests/test-qmp-input-strict$(EXESUF)
check-unit-y += tests/test-qmp-commands$(EXESUF)
check-unit-y += tests/test-string-input-visitor$(EXESUF)
check-unit-y += tests/test-string-output-visitor$(EXESUF)
check-unit-y += tests/test-coroutine$(EXESUF)
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
check-qint: check-qint.o qint.o $(tools-obj-y)
check-qstring: check-qstring.o qstring.o $(tools-obj-y)
check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
check-qlist: check-qlist.o qlist.o qint.o $(tools-obj-y)
check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-input-strict.o \
test-string-input-visitor.o test-string-output-visitor.o \
test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \
tests/test-coroutine.o tests/test-string-output-visitor.o \
tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
tests/test-qmp-commands.o
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
test-qapi-obj-y += module.o
$(test-obj-y): $(GENERATED_HEADERS)
$(test-obj-y): QEMU_INCLUDES += -Itests
tests/check-qint$(EXESUF): tests/check-qint.o qint.o $(tools-obj-y)
tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o $(tools-obj-y)
tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o $(tools-obj-y)
tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o $(tools-obj-y)
tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y)
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y)
tests/test-qapi-types.c tests/test-qapi-types.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(qapi-dir)/test-qapi-visit.c $(qapi-dir)/test-qapi-visit.h :\
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-qapi-visit.c tests/test-qapi-visit.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(qapi-dir)/test-qmp-commands.h $(qapi-dir)/test-qmp-marshal.c :\
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-qmp-commands.h tests/test-qmp-marshal.c :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y)
tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y)
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
.PHONY: check-help
check-help:
@echo "Regression testing targets:"
@echo
@echo " make check Run all tests"
@echo " make check-unit Run qobject tests"
@echo " make check-block Run block tests"
@echo " make check-report.html Generates an HTML test report"
@echo
@echo "Please note that HTML reports do not regenerate if the unit tests"
@echo "has not changed."
@echo
@echo "The variable SPEED can be set to control the gtester speed setting."
@echo "Default options are -k and (for make V=1) --verbose; they can be"
@echo "changed with variable GTESTER_OPTIONS."
test-qmp-input-strict.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-qmp-input-strict: test-qmp-input-strict.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
.SECONDARY:
test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
SPEED = quick
GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
test-qmp-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-qmp-input-visitor: test-qmp-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
# gtester tests, possibly with verbose output
test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
.PHONY: $(patsubst %, check-%, $(check-unit-y))
$(patsubst %, check-%, $(check-unit-y)): check-%: %
$(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
$(SRC_PATH)/tests/qemu-iotests-quick.sh: qemu-img qemu-io
# gtester tests with XML output
check-report-unit.xml: $(check-unit-y)
$(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@")
# Reports and overall runs
check-report.xml: check-report-unit.xml
$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@")
check-report.html: check-report.xml
$(call quiet-command,gtester-report $< > $@, " GEN $@")
.PHONY: check check-block
# Other tests
check: $(CHECKS)
$(call quiet-command, gtester $(CHECKS), " CHECK")
.PHONY: check-tests/qemu-iotests-quick.sh
check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF)
$<
check-block:
$(call quiet-command, $(SHELL) $(SRC_PATH)/tests/check-block.sh , " CHECK")
# Consolidated targets
.PHONY: check-unit check
check-unit: $(patsubst %,check-%, $(check-unit-y))
check-block: $(patsubst %,check-%, $(check-block-y))
check: check-unit

378
tests/check-qdict.c Normal file
View file

@ -0,0 +1,378 @@
/*
* QDict unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#include <glib.h>
#include "qint.h"
#include "qdict.h"
#include "qstring.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
static void qdict_new_test(void)
{
QDict *qdict;
qdict = qdict_new();
g_assert(qdict != NULL);
g_assert(qdict_size(qdict) == 0);
g_assert(qdict->base.refcnt == 1);
g_assert(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT);
// destroy doesn't exit yet
g_free(qdict);
}
static void qdict_put_obj_test(void)
{
QInt *qi;
QDict *qdict;
QDictEntry *ent;
const int num = 42;
qdict = qdict_new();
// key "" will have tdb hash 12345
qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
g_assert(qdict_size(qdict) == 1);
ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
qi = qobject_to_qint(ent->value);
g_assert(qint_get_int(qi) == num);
// destroy doesn't exit yet
QDECREF(qi);
g_free(ent->key);
g_free(ent);
g_free(qdict);
}
static void qdict_destroy_simple_test(void)
{
QDict *qdict;
qdict = qdict_new();
qdict_put_obj(qdict, "num", QOBJECT(qint_from_int(0)));
qdict_put_obj(qdict, "str", QOBJECT(qstring_from_str("foo")));
QDECREF(qdict);
}
static void qdict_get_test(void)
{
QInt *qi;
QObject *obj;
const int value = -42;
const char *key = "test";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qint_from_int(value));
obj = qdict_get(tests_dict, key);
g_assert(obj != NULL);
qi = qobject_to_qint(obj);
g_assert(qint_get_int(qi) == value);
QDECREF(tests_dict);
}
static void qdict_get_int_test(void)
{
int ret;
const int value = 100;
const char *key = "int";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qint_from_int(value));
ret = qdict_get_int(tests_dict, key);
g_assert(ret == value);
QDECREF(tests_dict);
}
static void qdict_get_try_int_test(void)
{
int ret;
const int value = 100;
const char *key = "int";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qint_from_int(value));
ret = qdict_get_try_int(tests_dict, key, 0);
g_assert(ret == value);
QDECREF(tests_dict);
}
static void qdict_get_str_test(void)
{
const char *p;
const char *key = "key";
const char *str = "string";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qstring_from_str(str));
p = qdict_get_str(tests_dict, key);
g_assert(p != NULL);
g_assert(strcmp(p, str) == 0);
QDECREF(tests_dict);
}
static void qdict_get_try_str_test(void)
{
const char *p;
const char *key = "key";
const char *str = "string";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qstring_from_str(str));
p = qdict_get_try_str(tests_dict, key);
g_assert(p != NULL);
g_assert(strcmp(p, str) == 0);
QDECREF(tests_dict);
}
static void qdict_haskey_not_test(void)
{
QDict *tests_dict = qdict_new();
g_assert(qdict_haskey(tests_dict, "test") == 0);
QDECREF(tests_dict);
}
static void qdict_haskey_test(void)
{
const char *key = "test";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qint_from_int(0));
g_assert(qdict_haskey(tests_dict, key) == 1);
QDECREF(tests_dict);
}
static void qdict_del_test(void)
{
const char *key = "key test";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qstring_from_str("foo"));
g_assert(qdict_size(tests_dict) == 1);
qdict_del(tests_dict, key);
g_assert(qdict_size(tests_dict) == 0);
g_assert(qdict_haskey(tests_dict, key) == 0);
QDECREF(tests_dict);
}
static void qobject_to_qdict_test(void)
{
QDict *tests_dict = qdict_new();
g_assert(qobject_to_qdict(QOBJECT(tests_dict)) == tests_dict);
QDECREF(tests_dict);
}
static void qdict_iterapi_test(void)
{
int count;
const QDictEntry *ent;
QDict *tests_dict = qdict_new();
g_assert(qdict_first(tests_dict) == NULL);
qdict_put(tests_dict, "key1", qint_from_int(1));
qdict_put(tests_dict, "key2", qint_from_int(2));
qdict_put(tests_dict, "key3", qint_from_int(3));
count = 0;
for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
count++;
}
g_assert(count == qdict_size(tests_dict));
/* Do it again to test restarting */
count = 0;
for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
g_assert(qdict_haskey(tests_dict, qdict_entry_key(ent)) == 1);
count++;
}
g_assert(count == qdict_size(tests_dict));
QDECREF(tests_dict);
}
/*
* Errors test-cases
*/
static void qdict_put_exists_test(void)
{
int value;
const char *key = "exists";
QDict *tests_dict = qdict_new();
qdict_put(tests_dict, key, qint_from_int(1));
qdict_put(tests_dict, key, qint_from_int(2));
value = qdict_get_int(tests_dict, key);
g_assert(value == 2);
g_assert(qdict_size(tests_dict) == 1);
QDECREF(tests_dict);
}
static void qdict_get_not_exists_test(void)
{
QDict *tests_dict = qdict_new();
g_assert(qdict_get(tests_dict, "foo") == NULL);
QDECREF(tests_dict);
}
/*
* Stress test-case
*
* This is a lot big for a unit-test, but there is no other place
* to have it.
*/
static void remove_dots(char *string)
{
char *p = strchr(string, ':');
if (p)
*p = '\0';
}
static QString *read_line(FILE *file, char *key)
{
char value[128];
if (fscanf(file, "%127s%127s", key, value) == EOF) {
return NULL;
}
remove_dots(key);
return qstring_from_str(value);
}
#define reset_file(file) fseek(file, 0L, SEEK_SET)
static void qdict_stress_test(void)
{
size_t lines;
char key[128];
FILE *test_file;
QDict *qdict;
QString *value;
const char *test_file_path = "qdict-test-data.txt";
test_file = fopen(test_file_path, "r");
g_assert(test_file != NULL);
// Create the dict
qdict = qdict_new();
g_assert(qdict != NULL);
// Add everything from the test file
for (lines = 0;; lines++) {
value = read_line(test_file, key);
if (!value)
break;
qdict_put(qdict, key, value);
}
g_assert(qdict_size(qdict) == lines);
// Check if everything is really in there
reset_file(test_file);
for (;;) {
const char *str1, *str2;
value = read_line(test_file, key);
if (!value)
break;
str1 = qstring_get_str(value);
str2 = qdict_get_str(qdict, key);
g_assert(str2 != NULL);
g_assert(strcmp(str1, str2) == 0);
QDECREF(value);
}
// Delete everything
reset_file(test_file);
for (;;) {
value = read_line(test_file, key);
if (!value)
break;
qdict_del(qdict, key);
QDECREF(value);
g_assert(qdict_haskey(qdict, key) == 0);
}
fclose(test_file);
g_assert(qdict_size(qdict) == 0);
QDECREF(qdict);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/public/new", qdict_new_test);
g_test_add_func("/public/put_obj", qdict_put_obj_test);
g_test_add_func("/public/destroy_simple", qdict_destroy_simple_test);
/* Continue, but now with fixtures */
g_test_add_func("/public/get", qdict_get_test);
g_test_add_func("/public/get_int", qdict_get_int_test);
g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
g_test_add_func("/public/get_str", qdict_get_str_test);
g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
g_test_add_func("/public/haskey", qdict_haskey_test);
g_test_add_func("/public/del", qdict_del_test);
g_test_add_func("/public/to_qdict", qobject_to_qdict_test);
g_test_add_func("/public/iterapi", qdict_iterapi_test);
g_test_add_func("/errors/put_exists", qdict_put_exists_test);
g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
/* The Big one */
if (g_test_slow()) {
g_test_add_func("/stress/test", qdict_stress_test);
}
return g_test_run();
}

53
tests/check-qfloat.c Normal file
View file

@ -0,0 +1,53 @@
/*
* QFloat unit-tests.
*
* Copyright IBM, Corp. 2009
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include <glib.h>
#include "qfloat.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
static void qfloat_from_double_test(void)
{
QFloat *qf;
const double value = -42.23423;
qf = qfloat_from_double(value);
g_assert(qf != NULL);
g_assert(qf->value == value);
g_assert(qf->base.refcnt == 1);
g_assert(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
// destroy doesn't exit yet
g_free(qf);
}
static void qfloat_destroy_test(void)
{
QFloat *qf = qfloat_from_double(0.0);
QDECREF(qf);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/public/from_double", qfloat_from_double_test);
g_test_add_func("/public/destroy", qfloat_destroy_test);
return g_test_run();
}

87
tests/check-qint.c Normal file
View file

@ -0,0 +1,87 @@
/*
* QInt unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#include <glib.h>
#include "qint.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
static void qint_from_int_test(void)
{
QInt *qi;
const int value = -42;
qi = qint_from_int(value);
g_assert(qi != NULL);
g_assert(qi->value == value);
g_assert(qi->base.refcnt == 1);
g_assert(qobject_type(QOBJECT(qi)) == QTYPE_QINT);
// destroy doesn't exit yet
g_free(qi);
}
static void qint_destroy_test(void)
{
QInt *qi = qint_from_int(0);
QDECREF(qi);
}
static void qint_from_int64_test(void)
{
QInt *qi;
const int64_t value = 0x1234567890abcdefLL;
qi = qint_from_int(value);
g_assert((int64_t) qi->value == value);
QDECREF(qi);
}
static void qint_get_int_test(void)
{
QInt *qi;
const int value = 123456;
qi = qint_from_int(value);
g_assert(qint_get_int(qi) == value);
QDECREF(qi);
}
static void qobject_to_qint_test(void)
{
QInt *qi;
qi = qint_from_int(0);
g_assert(qobject_to_qint(QOBJECT(qi)) == qi);
QDECREF(qi);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/public/from_int", qint_from_int_test);
g_test_add_func("/public/destroy", qint_destroy_test);
g_test_add_func("/public/from_int64", qint_from_int64_test);
g_test_add_func("/public/get_int", qint_get_int_test);
g_test_add_func("/public/to_qint", qobject_to_qint_test);
return g_test_run();
}

728
tests/check-qjson.c Normal file
View file

@ -0,0 +1,728 @@
/*
* Copyright IBM, Corp. 2009
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include <glib.h>
#include "qstring.h"
#include "qint.h"
#include "qdict.h"
#include "qlist.h"
#include "qfloat.h"
#include "qbool.h"
#include "qjson.h"
#include "qemu-common.h"
static void escaped_string(void)
{
int i;
struct {
const char *encoded;
const char *decoded;
int skip;
} test_cases[] = {
{ "\"\\b\"", "\b" },
{ "\"\\f\"", "\f" },
{ "\"\\n\"", "\n" },
{ "\"\\r\"", "\r" },
{ "\"\\t\"", "\t" },
{ "\"/\"", "/" },
{ "\"\\/\"", "/", .skip = 1 },
{ "\"\\\\\"", "\\" },
{ "\"\\\"\"", "\"" },
{ "\"hello world \\\"embedded string\\\"\"",
"hello world \"embedded string\"" },
{ "\"hello world\\nwith new line\"", "hello world\nwith new line" },
{ "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
{ "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
{ "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
{}
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded);
if (test_cases[i].skip == 0) {
str = qobject_to_json(obj);
g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].encoded);
qobject_decref(obj);
}
QDECREF(str);
}
}
static void simple_string(void)
{
int i;
struct {
const char *encoded;
const char *decoded;
} test_cases[] = {
{ "\"hello world\"", "hello world" },
{ "\"the quick brown fox jumped over the fence\"",
"the quick brown fox jumped over the fence" },
{}
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
str = qobject_to_json(obj);
g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
qobject_decref(obj);
QDECREF(str);
}
}
static void single_quote_string(void)
{
int i;
struct {
const char *encoded;
const char *decoded;
} test_cases[] = {
{ "'hello world'", "hello world" },
{ "'the quick brown fox \\' jumped over the fence'",
"the quick brown fox ' jumped over the fence" },
{}
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
QDECREF(str);
}
}
static void vararg_string(void)
{
int i;
struct {
const char *decoded;
} test_cases[] = {
{ "hello world" },
{ "the quick brown fox jumped over the fence" },
{}
};
for (i = 0; test_cases[i].decoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_jsonf("%s", test_cases[i].decoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
QDECREF(str);
}
}
static void simple_number(void)
{
int i;
struct {
const char *encoded;
int64_t decoded;
int skip;
} test_cases[] = {
{ "0", 0 },
{ "1234", 1234 },
{ "1", 1 },
{ "-32", -32 },
{ "-0", 0, .skip = 1 },
{ },
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QInt *qint;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QINT);
qint = qobject_to_qint(obj);
g_assert(qint_get_int(qint) == test_cases[i].decoded);
if (test_cases[i].skip == 0) {
QString *str;
str = qobject_to_json(obj);
g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
QDECREF(str);
}
QDECREF(qint);
}
}
static void float_number(void)
{
int i;
struct {
const char *encoded;
double decoded;
int skip;
} test_cases[] = {
{ "32.43", 32.43 },
{ "0.222", 0.222 },
{ "-32.12313", -32.12313 },
{ "-32.20e-10", -32.20e-10, .skip = 1 },
{ },
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QFloat *qfloat;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QFLOAT);
qfloat = qobject_to_qfloat(obj);
g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded);
if (test_cases[i].skip == 0) {
QString *str;
str = qobject_to_json(obj);
g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
QDECREF(str);
}
QDECREF(qfloat);
}
}
static void vararg_number(void)
{
QObject *obj;
QInt *qint;
QFloat *qfloat;
int value = 0x2342;
int64_t value64 = 0x2342342343LL;
double valuef = 2.323423423;
obj = qobject_from_jsonf("%d", value);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QINT);
qint = qobject_to_qint(obj);
g_assert(qint_get_int(qint) == value);
QDECREF(qint);
obj = qobject_from_jsonf("%" PRId64, value64);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QINT);
qint = qobject_to_qint(obj);
g_assert(qint_get_int(qint) == value64);
QDECREF(qint);
obj = qobject_from_jsonf("%f", valuef);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QFLOAT);
qfloat = qobject_to_qfloat(obj);
g_assert(qfloat_get_double(qfloat) == valuef);
QDECREF(qfloat);
}
static void keyword_literal(void)
{
QObject *obj;
QBool *qbool;
QString *str;
obj = qobject_from_json("true");
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
g_assert(qbool_get_int(qbool) != 0);
str = qobject_to_json(obj);
g_assert(strcmp(qstring_get_str(str), "true") == 0);
QDECREF(str);
QDECREF(qbool);
obj = qobject_from_json("false");
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
g_assert(qbool_get_int(qbool) == 0);
str = qobject_to_json(obj);
g_assert(strcmp(qstring_get_str(str), "false") == 0);
QDECREF(str);
QDECREF(qbool);
obj = qobject_from_jsonf("%i", false);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
g_assert(qbool_get_int(qbool) == 0);
QDECREF(qbool);
obj = qobject_from_jsonf("%i", true);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
g_assert(qbool_get_int(qbool) != 0);
QDECREF(qbool);
}
typedef struct LiteralQDictEntry LiteralQDictEntry;
typedef struct LiteralQObject LiteralQObject;
struct LiteralQObject
{
int type;
union {
int64_t qint;
const char *qstr;
LiteralQDictEntry *qdict;
LiteralQObject *qlist;
} value;
};
struct LiteralQDictEntry
{
const char *key;
LiteralQObject value;
};
#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
typedef struct QListCompareHelper
{
int index;
LiteralQObject *objs;
int result;
} QListCompareHelper;
static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
static void compare_helper(QObject *obj, void *opaque)
{
QListCompareHelper *helper = opaque;
if (helper->result == 0) {
return;
}
if (helper->objs[helper->index].type == QTYPE_NONE) {
helper->result = 0;
return;
}
helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
}
static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
{
if (lhs->type != qobject_type(rhs)) {
return 0;
}
switch (lhs->type) {
case QTYPE_QINT:
return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
case QTYPE_QSTRING:
return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
case QTYPE_QDICT: {
int i;
for (i = 0; lhs->value.qdict[i].key; i++) {
QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
return 0;
}
}
return 1;
}
case QTYPE_QLIST: {
QListCompareHelper helper;
helper.index = 0;
helper.objs = lhs->value.qlist;
helper.result = 1;
qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
return helper.result;
}
default:
break;
}
return 0;
}
static void simple_dict(void)
{
int i;
struct {
const char *encoded;
LiteralQObject decoded;
} test_cases[] = {
{
.encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
.decoded = QLIT_QDICT(((LiteralQDictEntry[]){
{ "foo", QLIT_QINT(42) },
{ "bar", QLIT_QSTR("hello world") },
{ }
})),
}, {
.encoded = "{}",
.decoded = QLIT_QDICT(((LiteralQDictEntry[]){
{ }
})),
}, {
.encoded = "{\"foo\": 43}",
.decoded = QLIT_QDICT(((LiteralQDictEntry[]){
{ "foo", QLIT_QINT(43) },
{ }
})),
},
{ }
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QDICT);
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QDICT);
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
}
}
static void simple_list(void)
{
int i;
struct {
const char *encoded;
LiteralQObject decoded;
} test_cases[] = {
{
.encoded = "[43,42]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QINT(42),
{ }
})),
},
{
.encoded = "[43]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
{ }
})),
},
{
.encoded = "[]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
{ }
})),
},
{
.encoded = "[{}]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QDICT(((LiteralQDictEntry[]){
{},
})),
{},
})),
},
{ }
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QLIST);
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QLIST);
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
}
}
static void simple_whitespace(void)
{
int i;
struct {
const char *encoded;
LiteralQObject decoded;
} test_cases[] = {
{
.encoded = " [ 43 , 42 ]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QINT(42),
{ }
})),
},
{
.encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QDICT(((LiteralQDictEntry[]){
{ "h", QLIT_QSTR("b") },
{ }})),
QLIT_QLIST(((LiteralQObject[]){
{ }})),
QLIT_QINT(42),
{ }
})),
},
{
.encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QDICT(((LiteralQDictEntry[]){
{ "h", QLIT_QSTR("b") },
{ "a", QLIT_QINT(32) },
{ }})),
QLIT_QLIST(((LiteralQObject[]){
{ }})),
QLIT_QINT(42),
{ }
})),
},
{ }
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QLIST);
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QLIST);
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
}
}
static void simple_varargs(void)
{
QObject *embedded_obj;
QObject *obj;
LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(1),
QLIT_QINT(2),
QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(32),
QLIT_QINT(42),
{}})),
{}}));
embedded_obj = qobject_from_json("[32, 42]");
g_assert(embedded_obj != NULL);
obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
g_assert(obj != NULL);
g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
qobject_decref(obj);
}
static void empty_input(void)
{
const char *empty = "";
QObject *obj = qobject_from_json(empty);
g_assert(obj == NULL);
}
static void unterminated_string(void)
{
QObject *obj = qobject_from_json("\"abc");
g_assert(obj == NULL);
}
static void unterminated_sq_string(void)
{
QObject *obj = qobject_from_json("'abc");
g_assert(obj == NULL);
}
static void unterminated_escape(void)
{
QObject *obj = qobject_from_json("\"abc\\\"");
g_assert(obj == NULL);
}
static void unterminated_array(void)
{
QObject *obj = qobject_from_json("[32");
g_assert(obj == NULL);
}
static void unterminated_array_comma(void)
{
QObject *obj = qobject_from_json("[32,");
g_assert(obj == NULL);
}
static void invalid_array_comma(void)
{
QObject *obj = qobject_from_json("[32,}");
g_assert(obj == NULL);
}
static void unterminated_dict(void)
{
QObject *obj = qobject_from_json("{'abc':32");
g_assert(obj == NULL);
}
static void unterminated_dict_comma(void)
{
QObject *obj = qobject_from_json("{'abc':32,");
g_assert(obj == NULL);
}
static void invalid_dict_comma(void)
{
QObject *obj = qobject_from_json("{'abc':32,}");
g_assert(obj == NULL);
}
static void unterminated_literal(void)
{
QObject *obj = qobject_from_json("nul");
g_assert(obj == NULL);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/literals/string/simple", simple_string);
g_test_add_func("/literals/string/escaped", escaped_string);
g_test_add_func("/literals/string/single_quote", single_quote_string);
g_test_add_func("/literals/string/vararg", vararg_string);
g_test_add_func("/literals/number/simple", simple_number);
g_test_add_func("/literals/number/float", float_number);
g_test_add_func("/literals/number/vararg", vararg_number);
g_test_add_func("/literals/keyword", keyword_literal);
g_test_add_func("/dicts/simple_dict", simple_dict);
g_test_add_func("/lists/simple_list", simple_list);
g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
g_test_add_func("/varargs/simple_varargs", simple_varargs);
g_test_add_func("/errors/empty_input", empty_input);
g_test_add_func("/errors/unterminated/string", unterminated_string);
g_test_add_func("/errors/unterminated/escape", unterminated_escape);
g_test_add_func("/errors/unterminated/sq_string", unterminated_sq_string);
g_test_add_func("/errors/unterminated/array", unterminated_array);
g_test_add_func("/errors/unterminated/array_comma", unterminated_array_comma);
g_test_add_func("/errors/unterminated/dict", unterminated_dict);
g_test_add_func("/errors/unterminated/dict_comma", unterminated_dict_comma);
g_test_add_func("/errors/invalid_array_comma", invalid_array_comma);
g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma);
g_test_add_func("/errors/unterminated/literal", unterminated_literal);
return g_test_run();
}

127
tests/check-qlist.c Normal file
View file

@ -0,0 +1,127 @@
/*
* QList unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#include <glib.h>
#include "qint.h"
#include "qlist.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
static void qlist_new_test(void)
{
QList *qlist;
qlist = qlist_new();
g_assert(qlist != NULL);
g_assert(qlist->base.refcnt == 1);
g_assert(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST);
// destroy doesn't exist yet
g_free(qlist);
}
static void qlist_append_test(void)
{
QInt *qi;
QList *qlist;
QListEntry *entry;
qi = qint_from_int(42);
qlist = qlist_new();
qlist_append(qlist, qi);
entry = QTAILQ_FIRST(&qlist->head);
g_assert(entry != NULL);
g_assert(entry->value == QOBJECT(qi));
// destroy doesn't exist yet
QDECREF(qi);
g_free(entry);
g_free(qlist);
}
static void qobject_to_qlist_test(void)
{
QList *qlist;
qlist = qlist_new();
g_assert(qobject_to_qlist(QOBJECT(qlist)) == qlist);
// destroy doesn't exist yet
g_free(qlist);
}
static void qlist_destroy_test(void)
{
int i;
QList *qlist;
qlist = qlist_new();
for (i = 0; i < 42; i++)
qlist_append(qlist, qint_from_int(i));
QDECREF(qlist);
}
static int iter_called;
static const int iter_max = 42;
static void iter_func(QObject *obj, void *opaque)
{
QInt *qi;
g_assert(opaque == NULL);
qi = qobject_to_qint(obj);
g_assert(qi != NULL);
g_assert((qint_get_int(qi) >= 0) && (qint_get_int(qi) <= iter_max));
iter_called++;
}
static void qlist_iter_test(void)
{
int i;
QList *qlist;
qlist = qlist_new();
for (i = 0; i < iter_max; i++)
qlist_append(qlist, qint_from_int(i));
iter_called = 0;
qlist_iter(qlist, iter_func, NULL);
g_assert(iter_called == iter_max);
QDECREF(qlist);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/public/new", qlist_new_test);
g_test_add_func("/public/append", qlist_append_test);
g_test_add_func("/public/to_qlist", qobject_to_qlist_test);
g_test_add_func("/public/destroy", qlist_destroy_test);
g_test_add_func("/public/iter", qlist_iter_test);
return g_test_run();
}

107
tests/check-qstring.c Normal file
View file

@ -0,0 +1,107 @@
/*
* QString unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#include <glib.h>
#include "qstring.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
static void qstring_from_str_test(void)
{
QString *qstring;
const char *str = "QEMU";
qstring = qstring_from_str(str);
g_assert(qstring != NULL);
g_assert(qstring->base.refcnt == 1);
g_assert(strcmp(str, qstring->string) == 0);
g_assert(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
// destroy doesn't exit yet
g_free(qstring->string);
g_free(qstring);
}
static void qstring_destroy_test(void)
{
QString *qstring = qstring_from_str("destroy test");
QDECREF(qstring);
}
static void qstring_get_str_test(void)
{
QString *qstring;
const char *ret_str;
const char *str = "QEMU/KVM";
qstring = qstring_from_str(str);
ret_str = qstring_get_str(qstring);
g_assert(strcmp(ret_str, str) == 0);
QDECREF(qstring);
}
static void qstring_append_chr_test(void)
{
int i;
QString *qstring;
const char *str = "qstring append char unit-test";
qstring = qstring_new();
for (i = 0; str[i]; i++)
qstring_append_chr(qstring, str[i]);
g_assert(strcmp(str, qstring_get_str(qstring)) == 0);
QDECREF(qstring);
}
static void qstring_from_substr_test(void)
{
QString *qs;
qs = qstring_from_substr("virtualization", 3, 9);
g_assert(qs != NULL);
g_assert(strcmp(qstring_get_str(qs), "tualiza") == 0);
QDECREF(qs);
}
static void qobject_to_qstring_test(void)
{
QString *qstring;
qstring = qstring_from_str("foo");
g_assert(qobject_to_qstring(QOBJECT(qstring)) == qstring);
QDECREF(qstring);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/public/from_str", qstring_from_str_test);
g_test_add_func("/public/destroy", qstring_destroy_test);
g_test_add_func("/public/get_str", qstring_get_str_test);
g_test_add_func("/public/append_chr", qstring_append_chr_test);
g_test_add_func("/public/from_substr", qstring_from_substr_test);
g_test_add_func("/public/to_qstring", qobject_to_qstring_test);
return g_test_run();
}

219
tests/test-coroutine.c Normal file
View file

@ -0,0 +1,219 @@
/*
* Coroutine tests
*
* Copyright IBM, Corp. 2011
*
* Authors:
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
* See the COPYING.LIB file in the top-level directory.
*
*/
#include <glib.h>
#include "qemu-coroutine.h"
/*
* Check that qemu_in_coroutine() works
*/
static void coroutine_fn verify_in_coroutine(void *opaque)
{
g_assert(qemu_in_coroutine());
}
static void test_in_coroutine(void)
{
Coroutine *coroutine;
g_assert(!qemu_in_coroutine());
coroutine = qemu_coroutine_create(verify_in_coroutine);
qemu_coroutine_enter(coroutine, NULL);
}
/*
* Check that qemu_coroutine_self() works
*/
static void coroutine_fn verify_self(void *opaque)
{
g_assert(qemu_coroutine_self() == opaque);
}
static void test_self(void)
{
Coroutine *coroutine;
coroutine = qemu_coroutine_create(verify_self);
qemu_coroutine_enter(coroutine, coroutine);
}
/*
* Check that coroutines may nest multiple levels
*/
typedef struct {
unsigned int n_enter; /* num coroutines entered */
unsigned int n_return; /* num coroutines returned */
unsigned int max; /* maximum level of nesting */
} NestData;
static void coroutine_fn nest(void *opaque)
{
NestData *nd = opaque;
nd->n_enter++;
if (nd->n_enter < nd->max) {
Coroutine *child;
child = qemu_coroutine_create(nest);
qemu_coroutine_enter(child, nd);
}
nd->n_return++;
}
static void test_nesting(void)
{
Coroutine *root;
NestData nd = {
.n_enter = 0,
.n_return = 0,
.max = 128,
};
root = qemu_coroutine_create(nest);
qemu_coroutine_enter(root, &nd);
/* Must enter and return from max nesting level */
g_assert_cmpint(nd.n_enter, ==, nd.max);
g_assert_cmpint(nd.n_return, ==, nd.max);
}
/*
* Check that yield/enter transfer control correctly
*/
static void coroutine_fn yield_5_times(void *opaque)
{
bool *done = opaque;
int i;
for (i = 0; i < 5; i++) {
qemu_coroutine_yield();
}
*done = true;
}
static void test_yield(void)
{
Coroutine *coroutine;
bool done = false;
int i = -1; /* one extra time to return from coroutine */
coroutine = qemu_coroutine_create(yield_5_times);
while (!done) {
qemu_coroutine_enter(coroutine, &done);
i++;
}
g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
}
/*
* Check that creation, enter, and return work
*/
static void coroutine_fn set_and_exit(void *opaque)
{
bool *done = opaque;
*done = true;
}
static void test_lifecycle(void)
{
Coroutine *coroutine;
bool done = false;
/* Create, enter, and return from coroutine */
coroutine = qemu_coroutine_create(set_and_exit);
qemu_coroutine_enter(coroutine, &done);
g_assert(done); /* expect done to be true (first time) */
/* Repeat to check that no state affects this test */
done = false;
coroutine = qemu_coroutine_create(set_and_exit);
qemu_coroutine_enter(coroutine, &done);
g_assert(done); /* expect done to be true (second time) */
}
/*
* Lifecycle benchmark
*/
static void coroutine_fn empty_coroutine(void *opaque)
{
/* Do nothing */
}
static void perf_lifecycle(void)
{
Coroutine *coroutine;
unsigned int i, max;
double duration;
max = 1000000;
g_test_timer_start();
for (i = 0; i < max; i++) {
coroutine = qemu_coroutine_create(empty_coroutine);
qemu_coroutine_enter(coroutine, NULL);
}
duration = g_test_timer_elapsed();
g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
}
static void perf_nesting(void)
{
unsigned int i, maxcycles, maxnesting;
double duration;
maxcycles = 100000000;
maxnesting = 20000;
Coroutine *root;
NestData nd = {
.n_enter = 0,
.n_return = 0,
.max = maxnesting,
};
g_test_timer_start();
for (i = 0; i < maxcycles; i++) {
root = qemu_coroutine_create(nest);
qemu_coroutine_enter(root, &nd);
}
duration = g_test_timer_elapsed();
g_test_message("Nesting %u iterations of %u depth each: %f s\n",
maxcycles, maxnesting, duration);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/basic/lifecycle", test_lifecycle);
g_test_add_func("/basic/yield", test_yield);
g_test_add_func("/basic/nesting", test_nesting);
g_test_add_func("/basic/self", test_self);
g_test_add_func("/basic/in_coroutine", test_in_coroutine);
if (g_test_perf()) {
g_test_add_func("/perf/lifecycle", perf_lifecycle);
g_test_add_func("/perf/nesting", perf_nesting);
}
return g_test_run();
}

139
tests/test-qmp-commands.c Normal file
View file

@ -0,0 +1,139 @@
#include <glib.h>
#include "qemu-objects.h"
#include "test-qmp-commands.h"
#include "qapi/qmp-core.h"
#include "module.h"
void qmp_user_def_cmd(Error **errp)
{
}
void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
{
}
UserDefTwo * qmp_user_def_cmd2(UserDefOne * ud1a, UserDefOne * ud1b, Error **errp)
{
UserDefTwo *ret;
UserDefOne *ud1c = g_malloc0(sizeof(UserDefOne));
UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne));
ud1c->string = strdup(ud1a->string);
ud1c->integer = ud1a->integer;
ud1d->string = strdup(ud1b->string);
ud1d->integer = ud1b->integer;
ret = g_malloc0(sizeof(UserDefTwo));
ret->string = strdup("blah1");
ret->dict.string = strdup("blah2");
ret->dict.dict.userdef = ud1c;
ret->dict.dict.string = strdup("blah3");
ret->dict.has_dict2 = true;
ret->dict.dict2.userdef = ud1d;
ret->dict.dict2.string = strdup("blah4");
return ret;
}
/* test commands with no input and no return value */
static void test_dispatch_cmd(void)
{
QDict *req = qdict_new();
QObject *resp;
qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
qobject_decref(resp);
QDECREF(req);
}
/* test commands that return an error due to invalid parameters */
static void test_dispatch_cmd_error(void)
{
QDict *req = qdict_new();
QObject *resp;
qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(qdict_haskey(qobject_to_qdict(resp), "error"));
qobject_decref(resp);
QDECREF(req);
}
/* test commands that involve both input parameters and return values */
static void test_dispatch_cmd_io(void)
{
QDict *req = qdict_new();
QDict *args = qdict_new();
QDict *ud1a = qdict_new();
QDict *ud1b = qdict_new();
QObject *resp;
qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
qdict_put_obj(req, "arguments", QOBJECT(args));
qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
/* TODO: put in full payload and check for errors */
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
qobject_decref(resp);
QDECREF(req);
}
/* test generated dealloc functions for generated types */
static void test_dealloc_types(void)
{
UserDefOne *ud1test, *ud1a, *ud1b;
UserDefOneList *ud1list;
ud1test = g_malloc0(sizeof(UserDefOne));
ud1test->integer = 42;
ud1test->string = g_strdup("hi there 42");
qapi_free_UserDefOne(ud1test);
ud1a = g_malloc0(sizeof(UserDefOne));
ud1a->integer = 43;
ud1a->string = g_strdup("hi there 43");
ud1b = g_malloc0(sizeof(UserDefOne));
ud1b->integer = 44;
ud1b->string = g_strdup("hi there 44");
ud1list = g_malloc0(sizeof(UserDefOneList));
ud1list->value = ud1a;
ud1list->next = g_malloc0(sizeof(UserDefOneList));
ud1list->next->value = ud1b;
qapi_free_UserDefOneList(ud1list);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
module_call_init(MODULE_INIT_QAPI);
g_test_run();
return 0;
}

View file

@ -0,0 +1,234 @@
/*
* QMP Input Visitor unit-tests (strict mode).
*
* Copyright (C) 2011-2012 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
* Paolo Bonzini <pbonzini@redhat.com>
*
* 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 "qapi/qmp-input-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qemu-objects.h"
typedef struct TestInputVisitorData {
QObject *obj;
QmpInputVisitor *qiv;
} TestInputVisitorData;
static void validate_teardown(TestInputVisitorData *data,
const void *unused)
{
qobject_decref(data->obj);
data->obj = NULL;
if (data->qiv) {
qmp_input_visitor_cleanup(data->qiv);
data->qiv = 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 GCC_FMT_ATTR(2, 3)
Visitor *validate_test_init(TestInputVisitorData *data,
const char *json_string, ...)
{
Visitor *v;
va_list ap;
va_start(ap, json_string);
data->obj = qobject_from_jsonv(json_string, &ap);
va_end(ap);
g_assert(data->obj != NULL);
data->qiv = qmp_input_visitor_new_strict(data->obj);
g_assert(data->qiv != NULL);
v = qmp_input_get_visitor(data->qiv);
g_assert(v != NULL);
return v;
}
typedef struct TestStruct
{
int64_t integer;
bool boolean;
char *string;
} TestStruct;
static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp)
{
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp);
visit_type_int(v, &(*obj)->integer, "integer", errp);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
visit_type_str(v, &(*obj)->string, "string", errp);
visit_end_struct(v, errp);
}
static void test_validate_struct(TestInputVisitorData *data,
const void *unused)
{
TestStruct *p = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
visit_type_TestStruct(v, &p, NULL, &errp);
g_assert(!error_is_set(&errp));
g_free(p->string);
g_free(p);
}
static void test_validate_struct_nested(TestInputVisitorData *data,
const void *unused)
{
UserDefNested *udp = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
visit_type_UserDefNested(v, &udp, NULL, &errp);
g_assert(!error_is_set(&errp));
qapi_free_UserDefNested(udp);
}
static void test_validate_list(TestInputVisitorData *data,
const void *unused)
{
UserDefOneList *head = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
visit_type_UserDefOneList(v, &head, NULL, &errp);
g_assert(!error_is_set(&errp));
qapi_free_UserDefOneList(head);
}
static void test_validate_union(TestInputVisitorData *data,
const void *unused)
{
UserDefUnion *tmp = NULL;
Visitor *v;
Error *errp = NULL;
v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
visit_type_UserDefUnion(v, &tmp, NULL, &errp);
g_assert(!error_is_set(&errp));
qapi_free_UserDefUnion(tmp);
}
static void test_validate_fail_struct(TestInputVisitorData *data,
const void *unused)
{
TestStruct *p = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
visit_type_TestStruct(v, &p, NULL, &errp);
g_assert(error_is_set(&errp));
if (p) {
g_free(p->string);
}
g_free(p);
}
static void test_validate_fail_struct_nested(TestInputVisitorData *data,
const void *unused)
{
UserDefNested *udp = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
visit_type_UserDefNested(v, &udp, NULL, &errp);
g_assert(error_is_set(&errp));
qapi_free_UserDefNested(udp);
}
static void test_validate_fail_list(TestInputVisitorData *data,
const void *unused)
{
UserDefOneList *head = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
visit_type_UserDefOneList(v, &head, NULL, &errp);
g_assert(error_is_set(&errp));
qapi_free_UserDefOneList(head);
}
static void test_validate_fail_union(TestInputVisitorData *data,
const void *unused)
{
UserDefUnion *tmp = NULL;
Error *errp = NULL;
Visitor *v;
v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 }, 'extra': 'yyy' }");
visit_type_UserDefUnion(v, &tmp, NULL, &errp);
g_assert(error_is_set(&errp));
qapi_free_UserDefUnion(tmp);
}
static void validate_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,
validate_teardown);
}
int main(int argc, char **argv)
{
TestInputVisitorData testdata;
g_test_init(&argc, &argv, NULL);
validate_test_add("/visitor/input-strict/pass/struct",
&testdata, test_validate_struct);
validate_test_add("/visitor/input-strict/pass/struct-nested",
&testdata, test_validate_struct_nested);
validate_test_add("/visitor/input-strict/pass/list",
&testdata, test_validate_list);
validate_test_add("/visitor/input-strict/pass/union",
&testdata, test_validate_union);
validate_test_add("/visitor/input-strict/fail/struct",
&testdata, test_validate_fail_struct);
validate_test_add("/visitor/input-strict/fail/struct-nested",
&testdata, test_validate_fail_struct_nested);
validate_test_add("/visitor/input-strict/fail/list",
&testdata, test_validate_fail_list);
validate_test_add("/visitor/input-strict/fail/union",
&testdata, test_validate_fail_union);
g_test_run();
return 0;
}

View file

@ -0,0 +1,308 @@
/*
* QMP Input Visitor unit-tests.
*
* Copyright (C) 2011 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* 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 "qapi/qmp-input-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qemu-objects.h"
typedef struct TestInputVisitorData {
QObject *obj;
QmpInputVisitor *qiv;
} TestInputVisitorData;
static void visitor_input_teardown(TestInputVisitorData *data,
const void *unused)
{
qobject_decref(data->obj);
data->obj = NULL;
if (data->qiv) {
qmp_input_visitor_cleanup(data->qiv);
data->qiv = 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 GCC_FMT_ATTR(2, 3)
Visitor *visitor_input_test_init(TestInputVisitorData *data,
const char *json_string, ...)
{
Visitor *v;
va_list ap;
va_start(ap, json_string);
data->obj = qobject_from_jsonv(json_string, &ap);
va_end(ap);
g_assert(data->obj != NULL);
data->qiv = qmp_input_visitor_new(data->obj);
g_assert(data->qiv != NULL);
v = qmp_input_get_visitor(data->qiv);
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, "%" PRId64, value);
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);
}
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, "%f", value);
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, "%s", 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, "%s", 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->obj = NULL;
data->qiv = NULL;
}
typedef struct TestStruct
{
int64_t integer;
bool boolean;
char *string;
} TestStruct;
static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp)
{
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp);
visit_type_int(v, &(*obj)->integer, "integer", errp);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
visit_type_str(v, &(*obj)->string, "string", errp);
visit_end_struct(v, errp);
}
static void test_visitor_in_struct(TestInputVisitorData *data,
const void *unused)
{
TestStruct *p = NULL;
Error *errp = NULL;
Visitor *v;
v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
visit_type_TestStruct(v, &p, NULL, &errp);
g_assert(!error_is_set(&errp));
g_assert_cmpint(p->integer, ==, -42);
g_assert(p->boolean == true);
g_assert_cmpstr(p->string, ==, "foo");
g_free(p->string);
g_free(p);
}
static void check_and_free_str(char *str, const char *cmp)
{
g_assert_cmpstr(str, ==, cmp);
g_free(str);
}
static void test_visitor_in_struct_nested(TestInputVisitorData *data,
const void *unused)
{
UserDefNested *udp = NULL;
Error *errp = NULL;
Visitor *v;
v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
visit_type_UserDefNested(v, &udp, NULL, &errp);
g_assert(!error_is_set(&errp));
check_and_free_str(udp->string0, "string0");
check_and_free_str(udp->dict1.string1, "string1");
g_assert_cmpint(udp->dict1.dict2.userdef1->integer, ==, 42);
check_and_free_str(udp->dict1.dict2.userdef1->string, "string");
check_and_free_str(udp->dict1.dict2.string2, "string2");
g_assert(udp->dict1.has_dict3 == false);
g_free(udp->dict1.dict2.userdef1);
g_free(udp);
}
static void test_visitor_in_list(TestInputVisitorData *data,
const void *unused)
{
UserDefOneList *item, *head = NULL;
Error *errp = NULL;
Visitor *v;
int i;
v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
visit_type_UserDefOneList(v, &head, NULL, &errp);
g_assert(!error_is_set(&errp));
g_assert(head != NULL);
for (i = 0, item = head; item; item = item->next, i++) {
char string[12];
snprintf(string, sizeof(string), "string%d", i);
g_assert_cmpstr(item->value->string, ==, string);
g_assert_cmpint(item->value->integer, ==, 42 + i);
}
qapi_free_UserDefOneList(head);
}
static void test_visitor_in_union(TestInputVisitorData *data,
const void *unused)
{
Visitor *v;
Error *err = NULL;
UserDefUnion *tmp;
v = visitor_input_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
visit_type_UserDefUnion(v, &tmp, NULL, &err);
g_assert(err == NULL);
g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_B);
g_assert_cmpint(tmp->b->integer, ==, 42);
qapi_free_UserDefUnion(tmp);
}
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);
}
static void test_visitor_in_errors(TestInputVisitorData *data,
const void *unused)
{
TestStruct *p = NULL;
Error *errp = NULL;
Visitor *v;
v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }");
visit_type_TestStruct(v, &p, NULL, &errp);
g_assert(error_is_set(&errp));
g_assert(p->string == NULL);
g_free(p->string);
g_free(p);
}
int main(int argc, char **argv)
{
TestInputVisitorData in_visitor_data;
g_test_init(&argc, &argv, NULL);
input_visitor_test_add("/visitor/input/int",
&in_visitor_data, test_visitor_in_int);
input_visitor_test_add("/visitor/input/bool",
&in_visitor_data, test_visitor_in_bool);
input_visitor_test_add("/visitor/input/number",
&in_visitor_data, test_visitor_in_number);
input_visitor_test_add("/visitor/input/string",
&in_visitor_data, test_visitor_in_string);
input_visitor_test_add("/visitor/input/enum",
&in_visitor_data, test_visitor_in_enum);
input_visitor_test_add("/visitor/input/struct",
&in_visitor_data, test_visitor_in_struct);
input_visitor_test_add("/visitor/input/struct-nested",
&in_visitor_data, test_visitor_in_struct_nested);
input_visitor_test_add("/visitor/input/list",
&in_visitor_data, test_visitor_in_list);
input_visitor_test_add("/visitor/input/union",
&in_visitor_data, test_visitor_in_union);
input_visitor_test_add("/visitor/input/errors",
&in_visitor_data, test_visitor_in_errors);
g_test_run();
return 0;
}

View file

@ -0,0 +1,477 @@
/*
* QMP Output Visitor unit-tests.
*
* Copyright (C) 2011 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* 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 "qapi/qmp-output-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qemu-objects.h"
typedef struct TestOutputVisitorData {
QmpOutputVisitor *qov;
Visitor *ov;
} TestOutputVisitorData;
static void visitor_output_setup(TestOutputVisitorData *data,
const void *unused)
{
data->qov = qmp_output_visitor_new();
g_assert(data->qov != NULL);
data->ov = qmp_output_get_visitor(data->qov);
g_assert(data->ov != NULL);
}
static void visitor_output_teardown(TestOutputVisitorData *data,
const void *unused)
{
qmp_output_visitor_cleanup(data->qov);
data->qov = NULL;
data->ov = NULL;
}
static void test_visitor_out_int(TestOutputVisitorData *data,
const void *unused)
{
int64_t value = -42;
Error *errp = NULL;
QObject *obj;
visit_type_int(data->ov, &value, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QINT);
g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value);
qobject_decref(obj);
}
static void test_visitor_out_bool(TestOutputVisitorData *data,
const void *unused)
{
Error *errp = NULL;
bool value = true;
QObject *obj;
visit_type_bool(data->ov, &value, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QBOOL);
g_assert(qbool_get_int(qobject_to_qbool(obj)) == value);
qobject_decref(obj);
}
static void test_visitor_out_number(TestOutputVisitorData *data,
const void *unused)
{
double value = 3.14;
Error *errp = NULL;
QObject *obj;
visit_type_number(data->ov, &value, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QFLOAT);
g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value);
qobject_decref(obj);
}
static void test_visitor_out_string(TestOutputVisitorData *data,
const void *unused)
{
char *string = (char *) "Q E M U";
Error *errp = NULL;
QObject *obj;
visit_type_str(data->ov, &string, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string);
qobject_decref(obj);
}
static void test_visitor_out_no_string(TestOutputVisitorData *data,
const void *unused)
{
char *string = NULL;
Error *errp = NULL;
QObject *obj;
/* A null string should return "" */
visit_type_str(data->ov, &string, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
qobject_decref(obj);
}
static void test_visitor_out_enum(TestOutputVisitorData *data,
const void *unused)
{
Error *errp = NULL;
QObject *obj;
EnumOne i;
for (i = 0; i < ENUM_ONE_MAX; i++) {
visit_type_EnumOne(data->ov, &i, "unused", &errp);
g_assert(!error_is_set(&errp));
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QSTRING);
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
EnumOne_lookup[i]);
qobject_decref(obj);
}
}
static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
const void *unused)
{
EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
Error *errp;
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
errp = NULL;
visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
g_assert(error_is_set(&errp) == true);
error_free(errp);
}
}
typedef struct TestStruct
{
int64_t integer;
bool boolean;
char *string;
} TestStruct;
static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp)
{
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp);
visit_type_int(v, &(*obj)->integer, "integer", errp);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
visit_type_str(v, &(*obj)->string, "string", errp);
visit_end_struct(v, errp);
}
static void test_visitor_out_struct(TestOutputVisitorData *data,
const void *unused)
{
TestStruct test_struct = { .integer = 42,
.boolean = false,
.string = (char *) "foo"};
TestStruct *p = &test_struct;
Error *errp = NULL;
QObject *obj;
QDict *qdict;
visit_type_TestStruct(data->ov, &p, NULL, &errp);
g_assert(!error_is_set(&errp));
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QDICT);
qdict = qobject_to_qdict(obj);
g_assert_cmpint(qdict_size(qdict), ==, 3);
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, 0);
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo");
QDECREF(qdict);
}
static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
const void *unused)
{
int64_t value = 42;
Error *errp = NULL;
UserDefNested *ud2;
QObject *obj;
QDict *qdict, *dict1, *dict2, *dict3, *userdef;
const char *string = "user def string";
const char *strings[] = { "forty two", "forty three", "forty four",
"forty five" };
ud2 = g_malloc0(sizeof(*ud2));
ud2->string0 = g_strdup(strings[0]);
ud2->dict1.string1 = g_strdup(strings[1]);
ud2->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
ud2->dict1.dict2.userdef1->string = g_strdup(string);
ud2->dict1.dict2.userdef1->integer = value;
ud2->dict1.dict2.string2 = g_strdup(strings[2]);
ud2->dict1.has_dict3 = true;
ud2->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne));
ud2->dict1.dict3.userdef2->string = g_strdup(string);
ud2->dict1.dict3.userdef2->integer = value;
ud2->dict1.dict3.string3 = g_strdup(strings[3]);
visit_type_UserDefNested(data->ov, &ud2, "unused", &errp);
g_assert(!error_is_set(&errp));
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QDICT);
qdict = qobject_to_qdict(obj);
g_assert_cmpint(qdict_size(qdict), ==, 2);
g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]);
dict1 = qdict_get_qdict(qdict, "dict1");
g_assert_cmpint(qdict_size(dict1), ==, 3);
g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]);
dict2 = qdict_get_qdict(dict1, "dict2");
g_assert_cmpint(qdict_size(dict2), ==, 2);
g_assert_cmpstr(qdict_get_str(dict2, "string2"), ==, strings[2]);
userdef = qdict_get_qdict(dict2, "userdef1");
g_assert_cmpint(qdict_size(userdef), ==, 2);
g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
dict3 = qdict_get_qdict(dict1, "dict3");
g_assert_cmpint(qdict_size(dict3), ==, 2);
g_assert_cmpstr(qdict_get_str(dict3, "string3"), ==, strings[3]);
userdef = qdict_get_qdict(dict3, "userdef2");
g_assert_cmpint(qdict_size(userdef), ==, 2);
g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
QDECREF(qdict);
qapi_free_UserDefNested(ud2);
}
static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
const void *unused)
{
EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
UserDefOne u = { 0 }, *pu = &u;
Error *errp;
int i;
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
errp = NULL;
u.has_enum1 = true;
u.enum1 = bad_values[i];
visit_type_UserDefOne(data->ov, &pu, "unused", &errp);
g_assert(error_is_set(&errp) == true);
error_free(errp);
}
}
typedef struct TestStructList
{
TestStruct *value;
struct TestStructList *next;
} TestStructList;
static void visit_type_TestStructList(Visitor *v, TestStructList **obj,
const char *name, Error **errp)
{
GenericList *i, **head = (GenericList **)obj;
visit_start_list(v, name, errp);
for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) {
TestStructList *native_i = (TestStructList *)i;
visit_type_TestStruct(v, &native_i->value, NULL, errp);
}
visit_end_list(v, errp);
}
static void test_visitor_out_list(TestOutputVisitorData *data,
const void *unused)
{
char *value_str = (char *) "list value";
TestStructList *p, *head = NULL;
const int max_items = 10;
bool value_bool = true;
int value_int = 10;
Error *errp = NULL;
QListEntry *entry;
QObject *obj;
QList *qlist;
int i;
for (i = 0; i < max_items; i++) {
p = g_malloc0(sizeof(*p));
p->value = g_malloc0(sizeof(*p->value));
p->value->integer = value_int;
p->value->boolean = value_bool;
p->value->string = value_str;
p->next = head;
head = p;
}
visit_type_TestStructList(data->ov, &head, NULL, &errp);
g_assert(!error_is_set(&errp));
obj = qmp_output_get_qobject(data->qov);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QLIST);
qlist = qobject_to_qlist(obj);
g_assert(!qlist_empty(qlist));
i = 0;
QLIST_FOREACH_ENTRY(qlist, entry) {
QDict *qdict;
g_assert(qobject_type(entry->value) == QTYPE_QDICT);
qdict = qobject_to_qdict(entry->value);
g_assert_cmpint(qdict_size(qdict), ==, 3);
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int);
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool);
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str);
i++;
}
g_assert_cmpint(i, ==, max_items);
QDECREF(qlist);
for (p = head; p;) {
TestStructList *tmp = p->next;
g_free(p->value);
g_free(p);
p = tmp;
}
}
static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
const void *unused)
{
UserDefNestedList *p, *head = NULL;
const char string[] = "foo bar";
int i, max_count = 1024;
for (i = 0; i < max_count; i++) {
p = g_malloc0(sizeof(*p));
p->value = g_malloc0(sizeof(*p->value));
p->value->string0 = g_strdup(string);
p->value->dict1.string1 = g_strdup(string);
p->value->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
p->value->dict1.dict2.userdef1->string = g_strdup(string);
p->value->dict1.dict2.userdef1->integer = 42;
p->value->dict1.dict2.string2 = g_strdup(string);
p->value->dict1.has_dict3 = false;
p->next = head;
head = p;
}
qapi_free_UserDefNestedList(head);
}
static void test_visitor_out_union(TestOutputVisitorData *data,
const void *unused)
{
QObject *arg, *qvalue;
QDict *qdict, *value;
Error *err = NULL;
UserDefUnion *tmp = g_malloc0(sizeof(UserDefUnion));
tmp->kind = USER_DEF_UNION_KIND_A;
tmp->a = g_malloc0(sizeof(UserDefA));
tmp->a->boolean = true;
visit_type_UserDefUnion(data->ov, &tmp, NULL, &err);
g_assert(err == NULL);
arg = qmp_output_get_qobject(data->qov);
g_assert(qobject_type(arg) == QTYPE_QDICT);
qdict = qobject_to_qdict(arg);
g_assert_cmpstr(qdict_get_str(qdict, "type"), ==, "a");
qvalue = qdict_get(qdict, "data");
g_assert(data != NULL);
g_assert(qobject_type(qvalue) == QTYPE_QDICT);
value = qobject_to_qdict(qvalue);
g_assert_cmpint(qdict_get_bool(value, "boolean"), ==, true);
qapi_free_UserDefUnion(tmp);
QDECREF(qdict);
}
static void output_visitor_test_add(const char *testpath,
TestOutputVisitorData *data,
void (*test_func)(TestOutputVisitorData *data, const void *user_data))
{
g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
test_func, visitor_output_teardown);
}
int main(int argc, char **argv)
{
TestOutputVisitorData out_visitor_data;
g_test_init(&argc, &argv, NULL);
output_visitor_test_add("/visitor/output/int",
&out_visitor_data, test_visitor_out_int);
output_visitor_test_add("/visitor/output/bool",
&out_visitor_data, test_visitor_out_bool);
output_visitor_test_add("/visitor/output/number",
&out_visitor_data, test_visitor_out_number);
output_visitor_test_add("/visitor/output/string",
&out_visitor_data, test_visitor_out_string);
output_visitor_test_add("/visitor/output/no-string",
&out_visitor_data, test_visitor_out_no_string);
output_visitor_test_add("/visitor/output/enum",
&out_visitor_data, test_visitor_out_enum);
output_visitor_test_add("/visitor/output/enum-errors",
&out_visitor_data, test_visitor_out_enum_errors);
output_visitor_test_add("/visitor/output/struct",
&out_visitor_data, test_visitor_out_struct);
output_visitor_test_add("/visitor/output/struct-nested",
&out_visitor_data, test_visitor_out_struct_nested);
output_visitor_test_add("/visitor/output/struct-errors",
&out_visitor_data, test_visitor_out_struct_errors);
output_visitor_test_add("/visitor/output/list",
&out_visitor_data, test_visitor_out_list);
output_visitor_test_add("/visitor/output/list-qapi-free",
&out_visitor_data, test_visitor_out_list_qapi_free);
output_visitor_test_add("/visitor/output/union",
&out_visitor_data, test_visitor_out_union);
g_test_run();
return 0;
}

View file

@ -0,0 +1,195 @@
/*
* 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 "qapi/string-input-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qemu-objects.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;
}
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);
g_test_run();
return 0;
}

View file

@ -0,0 +1,188 @@
/*
* String Output Visitor unit-tests.
*
* Copyright (C) 2012 Red Hat Inc.
*
* Authors:
* Paolo Bonzini <pbonzini@redhat.com> (based on test-qmp-output-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 "qapi/string-output-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
#include "qemu-objects.h"
typedef struct TestOutputVisitorData {
StringOutputVisitor *sov;
Visitor *ov;
} TestOutputVisitorData;
static void visitor_output_setup(TestOutputVisitorData *data,
const void *unused)
{
data->sov = string_output_visitor_new();
g_assert(data->sov != NULL);
data->ov = string_output_get_visitor(data->sov);
g_assert(data->ov != NULL);
}
static void visitor_output_teardown(TestOutputVisitorData *data,
const void *unused)
{
string_output_visitor_cleanup(data->sov);
data->sov = NULL;
data->ov = NULL;
}
static void test_visitor_out_int(TestOutputVisitorData *data,
const void *unused)
{
int64_t value = -42;
Error *errp = NULL;
char *str;
visit_type_int(data->ov, &value, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
str = string_output_get_string(data->sov);
g_assert(str != NULL);
g_assert_cmpstr(str, ==, "-42");
g_free(str);
}
static void test_visitor_out_bool(TestOutputVisitorData *data,
const void *unused)
{
Error *errp = NULL;
bool value = true;
char *str;
visit_type_bool(data->ov, &value, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
str = string_output_get_string(data->sov);
g_assert(str != NULL);
g_assert_cmpstr(str, ==, "true");
g_free(str);
}
static void test_visitor_out_number(TestOutputVisitorData *data,
const void *unused)
{
double value = 3.14;
Error *errp = NULL;
char *str;
visit_type_number(data->ov, &value, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
str = string_output_get_string(data->sov);
g_assert(str != NULL);
g_assert_cmpstr(str, ==, "3.14");
g_free(str);
}
static void test_visitor_out_string(TestOutputVisitorData *data,
const void *unused)
{
char *string = (char *) "Q E M U";
Error *errp = NULL;
char *str;
visit_type_str(data->ov, &string, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
str = string_output_get_string(data->sov);
g_assert(str != NULL);
g_assert_cmpstr(str, ==, string);
g_free(str);
}
static void test_visitor_out_no_string(TestOutputVisitorData *data,
const void *unused)
{
char *string = NULL;
Error *errp = NULL;
char *str;
/* A null string should return "" */
visit_type_str(data->ov, &string, NULL, &errp);
g_assert(error_is_set(&errp) == 0);
str = string_output_get_string(data->sov);
g_assert(str != NULL);
g_assert_cmpstr(str, ==, "");
g_free(str);
}
static void test_visitor_out_enum(TestOutputVisitorData *data,
const void *unused)
{
Error *errp = NULL;
char *str;
EnumOne i;
for (i = 0; i < ENUM_ONE_MAX; i++) {
visit_type_EnumOne(data->ov, &i, "unused", &errp);
g_assert(!error_is_set(&errp));
str = string_output_get_string(data->sov);
g_assert(str != NULL);
g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
g_free(str);
}
}
static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
const void *unused)
{
EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
Error *errp;
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
errp = NULL;
visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
g_assert(error_is_set(&errp) == true);
error_free(errp);
}
}
static void output_visitor_test_add(const char *testpath,
TestOutputVisitorData *data,
void (*test_func)(TestOutputVisitorData *data, const void *user_data))
{
g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
test_func, visitor_output_teardown);
}
int main(int argc, char **argv)
{
TestOutputVisitorData out_visitor_data;
g_test_init(&argc, &argv, NULL);
output_visitor_test_add("/string-visitor/output/int",
&out_visitor_data, test_visitor_out_int);
output_visitor_test_add("/string-visitor/output/bool",
&out_visitor_data, test_visitor_out_bool);
output_visitor_test_add("/string-visitor/output/number",
&out_visitor_data, test_visitor_out_number);
output_visitor_test_add("/string-visitor/output/string",
&out_visitor_data, test_visitor_out_string);
output_visitor_test_add("/string-visitor/output/no-string",
&out_visitor_data, test_visitor_out_no_string);
output_visitor_test_add("/string-visitor/output/enum",
&out_visitor_data, test_visitor_out_enum);
output_visitor_test_add("/string-visitor/output/enum-errors",
&out_visitor_data, test_visitor_out_enum_errors);
g_test_run();
return 0;
}