Skip to content

Commit 57c327f

Browse files
trueptolemybonzini
authored andcommitted
rust/vmstate: Add unit test for vmstate_{of|struct} macro
Add a unit test to cover some patterns accepted by vmstate_of and vmstate_struct macros, which correspond to the following C version macros: * VMSTATE_BOOL_V * VMSTATE_U64 * VMSTATE_STRUCT_VARRAY_UINT8 * (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32 * VMSTATE_ARRAY Signed-off-by: Zhao Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 1998502 commit 57c327f

File tree

1 file changed

+156
-2
lines changed

1 file changed

+156
-2
lines changed

rust/qemu-api/tests/vmstate_tests.rs

Lines changed: 156 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
use std::{ffi::CStr, mem::size_of, slice};
66

77
use qemu_api::{
8-
bindings::{vmstate_info_int8, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags},
8+
bindings::{
9+
vmstate_info_bool, vmstate_info_int64, vmstate_info_int8, vmstate_info_uint64,
10+
vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
11+
},
912
c_str,
13+
cell::BqlCell,
1014
vmstate::{VMStateDescription, VMStateField},
11-
vmstate_fields, vmstate_of, vmstate_unused,
15+
vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused,
1216
zeroable::Zeroable,
1317
};
1418

@@ -132,3 +136,153 @@ fn test_vmstate_varray_multiply() {
132136
// The last VMStateField in VMSTATE_FOOA.
133137
assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
134138
}
139+
140+
// =========================== Test VMSTATE_FOOB ===========================
141+
// Test the use cases of the vmstate macro, corresponding to the following C
142+
// macro variants:
143+
// * VMSTATE_FOOB:
144+
// - VMSTATE_BOOL_V
145+
// - VMSTATE_U64
146+
// - VMSTATE_STRUCT_VARRAY_UINT8
147+
// - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
148+
// - VMSTATE_ARRAY
149+
#[repr(C)]
150+
#[derive(qemu_api_macros::offsets)]
151+
struct FooB {
152+
arr_a: [FooA; FOO_ARRAY_MAX],
153+
num_a: u8,
154+
arr_a_mul: [FooA; FOO_ARRAY_MAX],
155+
num_a_mul: u32,
156+
wrap: BqlCell<u64>,
157+
val: bool,
158+
// FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
159+
arr_i64: [i64; FOO_ARRAY_MAX],
160+
}
161+
162+
static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
163+
name: c_str!("foo_b").as_ptr(),
164+
version_id: 2,
165+
minimum_version_id: 1,
166+
fields: vmstate_fields! {
167+
vmstate_of!(FooB, val).with_version_id(2),
168+
vmstate_of!(FooB, wrap),
169+
vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
170+
vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
171+
vmstate_of!(FooB, arr_i64),
172+
},
173+
..Zeroable::ZERO
174+
};
175+
176+
#[test]
177+
fn test_vmstate_bool_v() {
178+
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
179+
180+
// 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
181+
assert_eq!(
182+
unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
183+
b"val\0"
184+
);
185+
assert_eq!(foo_fields[0].offset, 136);
186+
assert_eq!(foo_fields[0].num_offset, 0);
187+
assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
188+
assert_eq!(foo_fields[0].version_id, 2);
189+
assert_eq!(foo_fields[0].size, 1);
190+
assert_eq!(foo_fields[0].num, 0);
191+
assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
192+
assert!(foo_fields[0].vmsd.is_null());
193+
assert!(foo_fields[0].field_exists.is_none());
194+
}
195+
196+
#[test]
197+
fn test_vmstate_uint64() {
198+
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
199+
200+
// 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
201+
assert_eq!(
202+
unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
203+
b"wrap\0"
204+
);
205+
assert_eq!(foo_fields[1].offset, 128);
206+
assert_eq!(foo_fields[1].num_offset, 0);
207+
assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
208+
assert_eq!(foo_fields[1].version_id, 0);
209+
assert_eq!(foo_fields[1].size, 8);
210+
assert_eq!(foo_fields[1].num, 0);
211+
assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
212+
assert!(foo_fields[1].vmsd.is_null());
213+
assert!(foo_fields[1].field_exists.is_none());
214+
}
215+
216+
#[test]
217+
fn test_vmstate_struct_varray_uint8() {
218+
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
219+
220+
// 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
221+
// VMSTATE_STRUCT_VARRAY_UINT8)
222+
assert_eq!(
223+
unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
224+
b"arr_a\0"
225+
);
226+
assert_eq!(foo_fields[2].offset, 0);
227+
assert_eq!(foo_fields[2].num_offset, 60);
228+
assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
229+
assert_eq!(foo_fields[2].version_id, 1);
230+
assert_eq!(foo_fields[2].size, 20);
231+
assert_eq!(foo_fields[2].num, 0);
232+
assert_eq!(
233+
foo_fields[2].flags.0,
234+
VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
235+
);
236+
assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
237+
assert!(foo_fields[2].field_exists.is_none());
238+
}
239+
240+
#[test]
241+
fn test_vmstate_struct_varray_uint32_multiply() {
242+
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
243+
244+
// 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
245+
// (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
246+
assert_eq!(
247+
unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
248+
b"arr_a_mul\0"
249+
);
250+
assert_eq!(foo_fields[3].offset, 64);
251+
assert_eq!(foo_fields[3].num_offset, 124);
252+
assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
253+
assert_eq!(foo_fields[3].version_id, 2);
254+
assert_eq!(foo_fields[3].size, 20);
255+
assert_eq!(foo_fields[3].num, 32);
256+
assert_eq!(
257+
foo_fields[3].flags.0,
258+
VMStateFlags::VMS_STRUCT.0
259+
| VMStateFlags::VMS_VARRAY_UINT32.0
260+
| VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
261+
);
262+
assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
263+
assert!(foo_fields[3].field_exists.is_none());
264+
}
265+
266+
#[test]
267+
fn test_vmstate_macro_array() {
268+
let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
269+
270+
// 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
271+
// VMSTATE_ARRAY)
272+
assert_eq!(
273+
unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
274+
b"arr_i64\0"
275+
);
276+
assert_eq!(foo_fields[4].offset, 144);
277+
assert_eq!(foo_fields[4].num_offset, 0);
278+
assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
279+
assert_eq!(foo_fields[4].version_id, 0);
280+
assert_eq!(foo_fields[4].size, 8);
281+
assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
282+
assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
283+
assert!(foo_fields[4].vmsd.is_null());
284+
assert!(foo_fields[4].field_exists.is_none());
285+
286+
// The last VMStateField in VMSTATE_FOOB.
287+
assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
288+
}

0 commit comments

Comments
 (0)