summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include137
-rw-r--r--tests/fp/Makefile3
m---------tests/fp/berkeley-testfloat-30
-rw-r--r--tests/fp/fp-bench.c15
-rw-r--r--tests/fp/fp-test.c4
-rw-r--r--tests/fp/platform.h1
-rwxr-xr-xtests/qemu-iotests/23847
-rw-r--r--tests/qemu-iotests/238.out6
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/test-io-channel-socket.c86
-rw-r--r--tests/test-vmstate.c50
11 files changed, 327 insertions, 23 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3453579af3..19b4c0a696 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -12,6 +12,7 @@ check-help:
@echo " $(MAKE) check-qapi-schema Run QAPI schema tests"
@echo " $(MAKE) check-block Run block tests"
@echo " $(MAKE) check-tcg Run TCG tests"
+ @echo " $(MAKE) check-softfloat Run FPU emulation tests"
@echo " $(MAKE) check-acceptance Run all acceptance (functional) tests"
@echo
@echo " $(MAKE) check-report.html Generates an HTML test report"
@@ -880,6 +881,138 @@ check-report-unit.tap: $(check-unit-y)
check-report.tap: $(patsubst %,check-report-qtest-%.tap, $(QTEST_TARGETS)) check-report-unit.tap
$(call quiet-command,./scripts/tap-merge.py $^ > $@,"GEN","$@")
+# FPU Emulation tests (aka softfloat)
+#
+# As we still have some places that need fixing the rules are a little
+# more complex than they need to be and have to override some of the
+# generic Makefile expansions. Once we are cleanly passing all
+# the tests we can simplify the make syntax.
+
+FP_TEST_BIN=$(BUILD_DIR)/tests/fp/fp-test
+
+# the build dir is created by configure
+.PHONY: $(FP_TEST_BIN)
+$(FP_TEST_BIN):
+ $(call quiet-command, \
+ $(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" $(notdir $@), \
+ "BUILD", "$(notdir $@)")
+
+# The full test suite can take a bit of time, default to a quick run
+ifeq ($(SPEED), quick)
+FP_TL=-l 1
+else
+FP_TL=-l 2 -r all
+endif
+
+# $1 = tests, $2 = description
+test-softfloat = $(call quiet-command, \
+ cd $(BUILD_DIR)/tests/fp && \
+ ./fp-test -s $(FP_TL) $1 > $2.out 2>&1 || \
+ (cat $2.out && exit 1;), \
+ "FLOAT TEST", $2)
+
+# Conversion Routines:
+# FIXME: i32_to_extF80 (broken), i64_to_extF80 (broken)
+# ui32_to_f128 (not implemented), f128_to_ui32 (not implemented)
+# extF80_roundToInt (broken)
+#
+check-softfloat-conv: $(FP_TEST_BIN)
+ $(call test-softfloat, \
+ i32_to_f16 i64_to_f16 \
+ i32_to_f32 i64_to_f32 \
+ i32_to_f64 i64_to_f64 \
+ i32_to_f128 i64_to_f128, int-to-float)
+ $(call test-softfloat, \
+ ui32_to_f16 ui64_to_f16 \
+ ui32_to_f32 ui64_to_f32 \
+ ui32_to_f64 ui64_to_f64 \
+ ui64_to_f128, uint-to-float)
+ $(call test-softfloat, \
+ f16_to_i32 f16_to_i32_r_minMag \
+ f32_to_i32 f32_to_i32_r_minMag \
+ f64_to_i32 f64_to_i32_r_minMag \
+ extF80_to_i32 extF80_to_i32_r_minMag \
+ f128_to_i32 f128_to_i32_r_minMag \
+ f16_to_i64 f16_to_i64_r_minMag \
+ f32_to_i64 f32_to_i64_r_minMag \
+ f64_to_i64 f64_to_i64_r_minMag \
+ extF80_to_i64 extF80_to_i64_r_minMag \
+ f128_to_i64 f128_to_i64_r_minMag, \
+ float-to-int)
+ $(call test-softfloat, \
+ f16_to_ui32 f16_to_ui32_r_minMag \
+ f32_to_ui32 f32_to_ui32_r_minMag \
+ f64_to_ui32 f64_to_ui32_r_minMag \
+ f16_to_ui64 f16_to_ui64_r_minMag \
+ f32_to_ui64 f32_to_ui64_r_minMag \
+ f64_to_ui64 f64_to_ui64_r_minMag, \
+ float-to-uint)
+ $(call test-softfloat, \
+ f16_roundToInt f32_roundToInt \
+ f64_roundToInt f128_roundToInt, \
+ round-to-integer)
+
+# Generic rule for all float operations
+#
+# Some patterns are overidden due to broken or missing tests.
+# Hopefully these can be removed over time.
+
+check-softfloat-%: $(FP_TEST_BIN)
+ $(call test-softfloat, f16_$* f32_$* f64_$* extF80_$* f128_$*, $*)
+
+# Float Compare routines
+SF_COMPARE_OPS=eq eq_signaling le le_quiet lt_quiet
+SF_COMPARE_RULES=$(patsubst %,check-softfloat-%, $(SF_COMPARE_OPS))
+
+# FIXME: extF80_le_quiet (broken)
+check-softfloat-le_quiet: $(FP_TEST_BIN)
+ $(call test-softfloat, \
+ f16_le_quiet f32_le_quiet f64_le_quiet \
+ f128_le_quiet, \
+ le_quiet)
+
+# FIXME: extF80_lt_quiet (broken)
+check-softfloat-lt_quiet: $(FP_TEST_BIN)
+ $(call test-softfloat, \
+ f16_lt_quiet f32_lt_quiet f64_lt_quiet \
+ f128_lt_quiet, \
+ lt_quiet)
+
+.PHONY: check-softfloat-compare
+check-softfloat-compare: $(SF_COMPARE_RULES)
+
+# Math Operations
+
+# FIXME: extF80_mulAdd (missing)
+check-softfloat-mulAdd: $(FP_TEST_BIN)
+ $(call test-softfloat, \
+ f16_mulAdd f32_mulAdd f64_mulAdd f128_mulAdd, \
+ mulAdd)
+
+# FIXME: extF80_rem (broken)
+check-softfloat-rem: $(FP_TEST_BIN)
+ $(call test-softfloat, \
+ f16_rem f32_rem f64_rem f128_rem, \
+ rem)
+
+SF_MATH_OPS=add sub mul mulAdd div rem sqrt
+SF_MATH_RULES=$(patsubst %,check-softfloat-%, $(SF_MATH_OPS))
+
+.PHONY: check-softfloat-ops
+check-softfloat-ops: $(SF_MATH_RULES)
+
+# Finally a generic rule to test all of softfoat. If TCG isnt't
+# enabled we define a null operation which skips the tests.
+
+.PHONY: check-softfloat
+ifeq ($(CONFIG_TCG),y)
+check-softfloat: check-softfloat-conv check-softfloat-compare check-softfloat-ops
+else
+check-softfloat:
+ $(call quiet-command, /bin/true, "FLOAT TEST", \
+ "SKIPPED for non-TCG builds")
+endif
+
# Per guest TCG tests
LINUX_USER_TARGETS=$(filter %-linux-user,$(TARGET_DIRS))
@@ -912,7 +1045,7 @@ clean-tcg-tests-%:
build-tcg: $(BUILD_TCG_TARGET_RULES)
.PHONY: check-tcg
-check-tcg: $(RUN_TCG_TARGET_RULES)
+check-tcg: check-softfloat $(RUN_TCG_TARGET_RULES)
.PHONY: clean-tcg
clean-tcg: $(CLEAN_TCG_TARGET_RULES)
@@ -993,7 +1126,7 @@ check-acceptance: check-venv $(TESTS_RESULTS_DIR)
check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y)) check-tests/qapi-schema/doc-good.texi
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
check-block: $(patsubst %,check-%, $(check-block-y))
-check: check-qapi-schema check-unit check-qtest check-decodetree
+check: check-qapi-schema check-unit check-softfloat check-qtest check-decodetree
check-clean:
rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y)) $(check-qtest-generic-y))
diff --git a/tests/fp/Makefile b/tests/fp/Makefile
index 5019dcdca0..5a35e7c210 100644
--- a/tests/fp/Makefile
+++ b/tests/fp/Makefile
@@ -65,8 +65,7 @@ QEMU_CFLAGS += $(TF_OPTS)
TF_CFLAGS :=
TF_CFLAGS += -Wno-strict-prototypes
TF_CFLAGS += -Wno-unknown-pragmas
-TF_CFLAGS += -Wno-discarded-qualifiers
-TF_CFLAGS += -Wno-maybe-uninitialized
+TF_CFLAGS += -Wno-uninitialized
TF_CFLAGS += -Wno-missing-prototypes
TF_CFLAGS += -Wno-return-type
TF_CFLAGS += -Wno-unused-function
diff --git a/tests/fp/berkeley-testfloat-3 b/tests/fp/berkeley-testfloat-3
-Subproject ca9fa2ba05625ba929958f163b01747e07dd39c
+Subproject 5a59dcec19327396a011a17fd924aed4fec416b
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
index f5bc5edebf..4ba5e1d2d4 100644
--- a/tests/fp/fp-bench.c
+++ b/tests/fp/fp-bench.c
@@ -143,15 +143,20 @@ static void update_random_ops(int n_ops, enum precision prec)
for (i = 0; i < n_ops; i++) {
uint64_t r = random_ops[i];
- if (prec == PREC_SINGLE || PREC_FLOAT32) {
+ switch (prec) {
+ case PREC_SINGLE:
+ case PREC_FLOAT32:
do {
r = xorshift64star(r);
} while (!float32_is_normal(r));
- } else if (prec == PREC_DOUBLE || PREC_FLOAT64) {
+ break;
+ case PREC_DOUBLE:
+ case PREC_FLOAT64:
do {
r = xorshift64star(r);
} while (!float64_is_normal(r));
- } else {
+ break;
+ default:
g_assert_not_reached();
}
random_ops[i] = r;
@@ -171,8 +176,6 @@ static void fill_random(union fp *ops, int n_ops, enum precision prec,
if (no_neg && float32_is_neg(ops[i].f32)) {
ops[i].f32 = float32_chs(ops[i].f32);
}
- /* raise the exponent to limit the frequency of denormal results */
- ops[i].f32 |= 0x40000000;
break;
case PREC_DOUBLE:
case PREC_FLOAT64:
@@ -180,8 +183,6 @@ static void fill_random(union fp *ops, int n_ops, enum precision prec,
if (no_neg && float64_is_neg(ops[i].f64)) {
ops[i].f64 = float64_chs(ops[i].f64);
}
- /* raise the exponent to limit the frequency of denormal results */
- ops[i].f64 |= LIT64(0x4000000000000000);
break;
default:
g_assert_not_reached();
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index fca576309c..2a35ef601d 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -789,7 +789,7 @@ static int set_init_flags(const char *flags)
return 0;
}
-static uint8_t slow_clear_flags(void)
+static uint_fast8_t slow_clear_flags(void)
{
uint8_t prev = slowfloat_exceptionFlags;
@@ -797,7 +797,7 @@ static uint8_t slow_clear_flags(void)
return prev;
}
-static uint8_t qemu_clear_flags(void)
+static uint_fast8_t qemu_clear_flags(void)
{
uint8_t prev = qemu_flags_to_sf(qsf.float_exception_flags);
diff --git a/tests/fp/platform.h b/tests/fp/platform.h
index f8c423dde3..c20ba70baa 100644
--- a/tests/fp/platform.h
+++ b/tests/fp/platform.h
@@ -29,6 +29,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config-host.h"
#ifndef HOST_WORDS_BIGENDIAN
#define LITTLEENDIAN 1
diff --git a/tests/qemu-iotests/238 b/tests/qemu-iotests/238
new file mode 100755
index 0000000000..f81ee1112f
--- /dev/null
+++ b/tests/qemu-iotests/238
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# Regression test for throttle group member unregister segfault with iothread
+#
+# Copyright (c) 2019 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import os
+import iotests
+from iotests import log
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
+
+from qemu import QEMUMachine
+
+if iotests.qemu_default_machine == 's390-ccw-virtio':
+ virtio_scsi_device = 'virtio-scsi-ccw'
+else:
+ virtio_scsi_device = 'virtio-scsi-pci'
+
+vm = QEMUMachine(iotests.qemu_prog)
+vm.add_args('-machine', 'accel=kvm')
+vm.launch()
+
+log(vm.qmp('blockdev-add', node_name='hd0', driver='null-co'))
+log(vm.qmp('object-add', qom_type='iothread', id='iothread0'))
+log(vm.qmp('device_add', id='scsi0', driver=virtio_scsi_device, iothread='iothread0'))
+log(vm.qmp('device_add', id='scsi-hd0', driver='scsi-hd', drive='hd0'))
+log(vm.qmp('block_set_io_throttle', id='scsi-hd0', bps=0, bps_rd=0, bps_wr=0,
+ iops=1000, iops_rd=0, iops_wr=0, conv_keys=False))
+log(vm.qmp('device_del', id='scsi-hd0'))
+
+vm.shutdown()
diff --git a/tests/qemu-iotests/238.out b/tests/qemu-iotests/238.out
new file mode 100644
index 0000000000..4de840ba8c
--- /dev/null
+++ b/tests/qemu-iotests/238.out
@@ -0,0 +1,6 @@
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index f6b245917a..0f1c3f9cdf 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -234,3 +234,4 @@
234 auto quick migration
235 auto quick
236 auto quick
+238 auto quick
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index 0597213f93..c253ae30f5 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -49,6 +49,7 @@ static void test_io_channel_set_socket_bufs(QIOChannel *src,
static void test_io_channel_setup_sync(SocketAddress *listen_addr,
SocketAddress *connect_addr,
+ QIOChannel **srv,
QIOChannel **src,
QIOChannel **dst)
{
@@ -78,7 +79,7 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr,
test_io_channel_set_socket_bufs(*src, *dst);
- object_unref(OBJECT(lioc));
+ *srv = QIO_CHANNEL(lioc);
}
@@ -99,6 +100,7 @@ static void test_io_channel_complete(QIOTask *task,
static void test_io_channel_setup_async(SocketAddress *listen_addr,
SocketAddress *connect_addr,
+ QIOChannel **srv,
QIOChannel **src,
QIOChannel **dst)
{
@@ -146,21 +148,34 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,
qio_channel_set_delay(*src, false);
test_io_channel_set_socket_bufs(*src, *dst);
- object_unref(OBJECT(lioc));
+ *srv = QIO_CHANNEL(lioc);
g_main_loop_unref(data.loop);
}
+static void test_io_channel_socket_path_exists(SocketAddress *addr,
+ bool expectExists)
+{
+ if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
+ return;
+ }
+
+ g_assert(g_file_test(addr->u.q_unix.path,
+ G_FILE_TEST_EXISTS) == expectExists);
+}
+
+
static void test_io_channel(bool async,
SocketAddress *listen_addr,
SocketAddress *connect_addr,
bool passFD)
{
- QIOChannel *src, *dst;
+ QIOChannel *src, *dst, *srv;
QIOChannelTest *test;
if (async) {
- test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst);
+ test_io_channel_setup_async(listen_addr, connect_addr,
+ &srv, &src, &dst);
g_assert(!passFD ||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
@@ -169,14 +184,25 @@ static void test_io_channel(bool async,
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
+ test_io_channel_socket_path_exists(listen_addr, true);
+
test = qio_channel_test_new();
qio_channel_test_run_threads(test, true, src, dst);
qio_channel_test_validate(test);
+ test_io_channel_socket_path_exists(listen_addr, true);
+
+ /* unref without close, to ensure finalize() cleans up */
+
object_unref(OBJECT(src));
object_unref(OBJECT(dst));
+ test_io_channel_socket_path_exists(listen_addr, true);
- test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst);
+ object_unref(OBJECT(srv));
+ test_io_channel_socket_path_exists(listen_addr, false);
+
+ test_io_channel_setup_async(listen_addr, connect_addr,
+ &srv, &src, &dst);
g_assert(!passFD ||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
@@ -189,10 +215,24 @@ static void test_io_channel(bool async,
qio_channel_test_run_threads(test, false, src, dst);
qio_channel_test_validate(test);
+ /* close before unref, to ensure finalize copes with already closed */
+
+ qio_channel_close(src, &error_abort);
+ qio_channel_close(dst, &error_abort);
+ test_io_channel_socket_path_exists(listen_addr, true);
+
object_unref(OBJECT(src));
object_unref(OBJECT(dst));
+ test_io_channel_socket_path_exists(listen_addr, true);
+
+ qio_channel_close(srv, &error_abort);
+ test_io_channel_socket_path_exists(listen_addr, false);
+
+ object_unref(OBJECT(srv));
+ test_io_channel_socket_path_exists(listen_addr, false);
} else {
- test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
+ test_io_channel_setup_sync(listen_addr, connect_addr,
+ &srv, &src, &dst);
g_assert(!passFD ||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
@@ -201,14 +241,25 @@ static void test_io_channel(bool async,
g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN));
g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN));
+ test_io_channel_socket_path_exists(listen_addr, true);
+
test = qio_channel_test_new();
qio_channel_test_run_threads(test, true, src, dst);
qio_channel_test_validate(test);
+ test_io_channel_socket_path_exists(listen_addr, true);
+
+ /* unref without close, to ensure finalize() cleans up */
+
object_unref(OBJECT(src));
object_unref(OBJECT(dst));
+ test_io_channel_socket_path_exists(listen_addr, true);
+
+ object_unref(OBJECT(srv));
+ test_io_channel_socket_path_exists(listen_addr, false);
- test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
+ test_io_channel_setup_sync(listen_addr, connect_addr,
+ &srv, &src, &dst);
g_assert(!passFD ||
qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS));
@@ -221,8 +272,23 @@ static void test_io_channel(bool async,
qio_channel_test_run_threads(test, false, src, dst);
qio_channel_test_validate(test);
+ test_io_channel_socket_path_exists(listen_addr, true);
+
+ /* close before unref, to ensure finalize copes with already closed */
+
+ qio_channel_close(src, &error_abort);
+ qio_channel_close(dst, &error_abort);
+ test_io_channel_socket_path_exists(listen_addr, true);
+
object_unref(OBJECT(src));
object_unref(OBJECT(dst));
+ test_io_channel_socket_path_exists(listen_addr, true);
+
+ qio_channel_close(srv, &error_abort);
+ test_io_channel_socket_path_exists(listen_addr, false);
+
+ object_unref(OBJECT(srv));
+ test_io_channel_socket_path_exists(listen_addr, false);
}
}
@@ -316,7 +382,6 @@ static void test_io_channel_unix(bool async)
qapi_free_SocketAddress(listen_addr);
qapi_free_SocketAddress(connect_addr);
- g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS) == FALSE);
}
@@ -335,7 +400,7 @@ static void test_io_channel_unix_fd_pass(void)
{
SocketAddress *listen_addr = g_new0(SocketAddress, 1);
SocketAddress *connect_addr = g_new0(SocketAddress, 1);
- QIOChannel *src, *dst;
+ QIOChannel *src, *dst, *srv;
int testfd;
int fdsend[3];
int *fdrecv = NULL;
@@ -359,7 +424,7 @@ static void test_io_channel_unix_fd_pass(void)
connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
- test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
+ test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst);
memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend));
@@ -412,6 +477,7 @@ static void test_io_channel_unix_fd_pass(void)
object_unref(OBJECT(src));
object_unref(OBJECT(dst));
+ object_unref(OBJECT(srv));
qapi_free_SocketAddress(listen_addr);
qapi_free_SocketAddress(connect_addr);
unlink(TEST_SOCKET);
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index 0ab29a8216..fc8ce62471 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -284,6 +284,55 @@ static void test_simple_primitive(void)
FIELD_EQUAL(i64_2);
}
+typedef struct TestSimpleArray {
+ uint16_t u16_1[3];
+} TestSimpleArray;
+
+/* Object instantiation, we are going to use it in more than one test */
+
+TestSimpleArray obj_simple_arr = {
+ .u16_1 = { 0x42, 0x43, 0x44 },
+};
+
+/* Description of the values. If you add a primitive type
+ you are expected to add a test here */
+
+static const VMStateDescription vmstate_simple_arr = {
+ .name = "simple/array",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16_ARRAY(u16_1, TestSimpleArray, 3),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+uint8_t wire_simple_arr[] = {
+ /* u16_1 */ 0x00, 0x42,
+ /* u16_1 */ 0x00, 0x43,
+ /* u16_1 */ 0x00, 0x44,
+ QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
+};
+
+static void obj_simple_arr_copy(void *target, void *source)
+{
+ memcpy(target, source, sizeof(TestSimpleArray));
+}
+
+static void test_simple_array(void)
+{
+ TestSimpleArray obj, obj_clone;
+
+ memset(&obj, 0, sizeof(obj));
+ save_vmstate(&vmstate_simple_arr, &obj_simple_arr);
+
+ compare_vmstate(wire_simple_arr, sizeof(wire_simple_arr));
+
+ SUCCESS(load_vmstate(&vmstate_simple_arr, &obj, &obj_clone,
+ obj_simple_arr_copy, 1, wire_simple_arr,
+ sizeof(wire_simple_arr)));
+}
+
typedef struct TestStruct {
uint32_t a, b, c, e;
uint64_t d, f;
@@ -863,6 +912,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
+ g_test_add_func("/vmstate/simple/array", test_simple_array);
g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);