mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-02 23:33:54 -06:00
rust/vmstate: Add unit test for vmstate_of macro
The vmstate has too many combinations of VMStateFlags and VMStateField. Currently, the best way to test is to ensure that the Rust vmstate definition is consistent with the (possibly corresponding) C version. Add a unit test to cover some patterns accepted by vmstate_of macro, which correspond to the following C version macros: * VMSTATE_U16 * VMSTATE_UNUSED * VMSTATE_VARRAY_UINT16_UNSAFE * VMSTATE_VARRAY_MULTIPLY Note: Because vmstate_info_* are defined in vmstate-types.c, it's necessary to link libmigration to rust unit tests. In the future, maybe it's possible to spilt libmigration from rust_qemu_api_objs. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Link: https://lore.kernel.org/r/20250318130219.1799170-12-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
b131003721
commit
1998502196
3 changed files with 139 additions and 2 deletions
|
@ -58,7 +58,8 @@ rust_qemu_api_objs = static_library(
|
|||
libchardev.extract_all_objects(recursive: false),
|
||||
libcrypto.extract_all_objects(recursive: false),
|
||||
libauthz.extract_all_objects(recursive: false),
|
||||
libio.extract_all_objects(recursive: false)])
|
||||
libio.extract_all_objects(recursive: false),
|
||||
libmigration.extract_all_objects(recursive: false)])
|
||||
rust_qemu_api_deps = declare_dependency(
|
||||
dependencies: [
|
||||
qom_ss.dependencies(),
|
||||
|
@ -71,7 +72,7 @@ rust_qemu_api_deps = declare_dependency(
|
|||
test('rust-qemu-api-integration',
|
||||
executable(
|
||||
'rust-qemu-api-integration',
|
||||
'tests/tests.rs',
|
||||
files('tests/tests.rs', 'tests/vmstate_tests.rs'),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_args: ['--test'],
|
||||
install: false,
|
||||
|
|
|
@ -17,6 +17,8 @@ use qemu_api::{
|
|||
zeroable::Zeroable,
|
||||
};
|
||||
|
||||
mod vmstate_tests;
|
||||
|
||||
// Test that macros can compile.
|
||||
pub static VMSTATE: VMStateDescription = VMStateDescription {
|
||||
name: c_str!("name").as_ptr(),
|
||||
|
|
134
rust/qemu-api/tests/vmstate_tests.rs
Normal file
134
rust/qemu-api/tests/vmstate_tests.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
// Copyright (C) 2025 Intel Corporation.
|
||||
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::{ffi::CStr, mem::size_of, slice};
|
||||
|
||||
use qemu_api::{
|
||||
bindings::{vmstate_info_int8, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags},
|
||||
c_str,
|
||||
vmstate::{VMStateDescription, VMStateField},
|
||||
vmstate_fields, vmstate_of, vmstate_unused,
|
||||
zeroable::Zeroable,
|
||||
};
|
||||
|
||||
const FOO_ARRAY_MAX: usize = 3;
|
||||
|
||||
// =========================== Test VMSTATE_FOOA ===========================
|
||||
// Test the use cases of the vmstate macro, corresponding to the following C
|
||||
// macro variants:
|
||||
// * VMSTATE_FOOA:
|
||||
// - VMSTATE_U16
|
||||
// - VMSTATE_UNUSED
|
||||
// - VMSTATE_VARRAY_UINT16_UNSAFE
|
||||
// - VMSTATE_VARRAY_MULTIPLY
|
||||
#[repr(C)]
|
||||
#[derive(qemu_api_macros::offsets)]
|
||||
struct FooA {
|
||||
arr: [u8; FOO_ARRAY_MAX],
|
||||
num: u16,
|
||||
arr_mul: [i8; FOO_ARRAY_MAX],
|
||||
num_mul: u32,
|
||||
elem: i8,
|
||||
}
|
||||
|
||||
static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
|
||||
name: c_str!("foo_a").as_ptr(),
|
||||
version_id: 1,
|
||||
minimum_version_id: 1,
|
||||
fields: vmstate_fields! {
|
||||
vmstate_of!(FooA, elem),
|
||||
vmstate_unused!(size_of::<i64>()),
|
||||
vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
|
||||
vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
|
||||
},
|
||||
..Zeroable::ZERO
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_vmstate_uint16() {
|
||||
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
|
||||
|
||||
// 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
|
||||
assert_eq!(
|
||||
unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
|
||||
b"elem\0"
|
||||
);
|
||||
assert_eq!(foo_fields[0].offset, 16);
|
||||
assert_eq!(foo_fields[0].num_offset, 0);
|
||||
assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
|
||||
assert_eq!(foo_fields[0].version_id, 0);
|
||||
assert_eq!(foo_fields[0].size, 1);
|
||||
assert_eq!(foo_fields[0].num, 0);
|
||||
assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
|
||||
assert!(foo_fields[0].vmsd.is_null());
|
||||
assert!(foo_fields[0].field_exists.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmstate_unused() {
|
||||
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
|
||||
|
||||
// 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
|
||||
assert_eq!(
|
||||
unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
|
||||
b"unused\0"
|
||||
);
|
||||
assert_eq!(foo_fields[1].offset, 0);
|
||||
assert_eq!(foo_fields[1].num_offset, 0);
|
||||
assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
|
||||
assert_eq!(foo_fields[1].version_id, 0);
|
||||
assert_eq!(foo_fields[1].size, 8);
|
||||
assert_eq!(foo_fields[1].num, 0);
|
||||
assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
|
||||
assert!(foo_fields[1].vmsd.is_null());
|
||||
assert!(foo_fields[1].field_exists.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmstate_varray_uint16_unsafe() {
|
||||
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
|
||||
|
||||
// 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
|
||||
// VMSTATE_VARRAY_UINT16_UNSAFE)
|
||||
assert_eq!(
|
||||
unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
|
||||
b"arr\0"
|
||||
);
|
||||
assert_eq!(foo_fields[2].offset, 0);
|
||||
assert_eq!(foo_fields[2].num_offset, 4);
|
||||
assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
|
||||
assert_eq!(foo_fields[2].version_id, 0);
|
||||
assert_eq!(foo_fields[2].size, 1);
|
||||
assert_eq!(foo_fields[2].num, 0);
|
||||
assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
|
||||
assert!(foo_fields[2].vmsd.is_null());
|
||||
assert!(foo_fields[2].field_exists.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmstate_varray_multiply() {
|
||||
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
|
||||
|
||||
// 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
|
||||
// VMSTATE_VARRAY_MULTIPLY)
|
||||
assert_eq!(
|
||||
unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
|
||||
b"arr_mul\0"
|
||||
);
|
||||
assert_eq!(foo_fields[3].offset, 6);
|
||||
assert_eq!(foo_fields[3].num_offset, 12);
|
||||
assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
|
||||
assert_eq!(foo_fields[3].version_id, 0);
|
||||
assert_eq!(foo_fields[3].size, 1);
|
||||
assert_eq!(foo_fields[3].num, 16);
|
||||
assert_eq!(
|
||||
foo_fields[3].flags.0,
|
||||
VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
|
||||
);
|
||||
assert!(foo_fields[3].vmsd.is_null());
|
||||
assert!(foo_fields[3].field_exists.is_none());
|
||||
|
||||
// The last VMStateField in VMSTATE_FOOA.
|
||||
assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue