diff options
| author | Stefan Hajnoczi <stefanha@redhat.com> | 2024-12-21 08:06:50 -0500 |
|---|---|---|
| committer | Stefan Hajnoczi <stefanha@redhat.com> | 2024-12-21 08:06:50 -0500 |
| commit | e3a207722b783675b362db4ae22a449f42a26b24 (patch) | |
| tree | 02593a73b81cc459bd7e645e688c1296b47cb741 /rust/qemu-api/tests | |
| parent | 9863d46a5a25bfff7d2195ad5e3127ab3bae0a2b (diff) | |
| parent | bf9987c06eb8274c2503174b944b8fbe94cc24d7 (diff) | |
| download | focaccia-qemu-e3a207722b783675b362db4ae22a449f42a26b24.tar.gz focaccia-qemu-e3a207722b783675b362db4ae22a449f42a26b24.zip | |
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* qdev: second part of Property cleanups * rust: second part of QOM rework * rust: callbacks wrapper * rust: pl011 bugfixes * kvm: cleanup errors in kvm_convert_memory() # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmdkaEkUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroN0/wgAgIJg8BrlRKfmiz14NZfph8/jarSj # TOWYVxL2v4q98KBuL5pta2ucObgzwqyqSyc02S2DGSOIMQCIiBB5MaCk1iMjx+BO # pmVU8gNlD8faO8SSmnnr+jDQt+G+bQ/nRgQJOAReF8oVw3O2aC/FaVKpitMzWtvv # PLnJWdrqqpGq14OzX8iNCzSujxppAuyjrhT4lNlekzDoDfdTez72r+rXkvg4GzZL # QC3xLYg/LrT8Rs+zgOhm/AaIyS4bOyMlkU9Du1rQ6Tyne45ey2FCwKVzBKrJdGcw # sVbzEclxseLenoTbZqYK6JTzLdDoThVUbY2JwoCGUaIm+74P4NjEsUsTVg== # =TuQM # -----END PGP SIGNATURE----- # gpg: Signature made Thu 19 Dec 2024 13:39:05 EST # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (42 commits) rust: pl011: simplify handling of the FIFO enabled bit in LCR rust: pl011: fix migration stream rust: pl011: extend registers to 32 bits rust: pl011: fix break errors and definition of Data struct rust: pl011: always use reset() method on registers rust: pl011: match break logic of C version rust: pl011: fix declaration of LineControl bits target/i386: Reset TSCs of parked vCPUs too on VM reset kvm: consistently return 0/-errno from kvm_convert_memory rust: qemu-api: add a module to wrap functions and zero-sized closures rust: qom: add initial subset of methods on Object rust: qom: add casting functionality rust: tests: allow writing more than one test bql: add a "mock" BQL for Rust unit tests rust: re-export C types from qemu-api submodules rust: rename qemu-api modules to follow C code a bit more rust: qom: add possibility of overriding unparent rust: qom: put class_init together from multiple ClassInitImpl<> Constify all opaque Property pointers hw/core/qdev-properties: Constify Property argument to PropertyInfo.print ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api/tests')
| -rw-r--r-- | rust/qemu-api/tests/tests.rs | 185 |
1 files changed, 138 insertions, 47 deletions
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index 278efe967f..1d2825b098 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -2,69 +2,160 @@ // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> // SPDX-License-Identifier: GPL-2.0-or-later -use std::ffi::CStr; +use std::{ + ffi::CStr, + os::raw::c_void, + ptr::{addr_of, addr_of_mut}, +}; use qemu_api::{ - bindings::*, c_str, declare_properties, define_property, definitions::ObjectImpl, - device_class::DeviceImpl, impl_device_class, prelude::*, zeroable::Zeroable, + bindings::*, + c_str, + cell::{self, BqlCell}, + declare_properties, define_property, + prelude::*, + qdev::{DeviceImpl, DeviceState, Property}, + qom::ObjectImpl, + vmstate::VMStateDescription, + zeroable::Zeroable, }; -#[test] -fn test_device_decl_macros() { - // Test that macros can compile. - pub static VMSTATE: VMStateDescription = VMStateDescription { - name: c_str!("name").as_ptr(), - unmigratable: true, - ..Zeroable::ZERO - }; - - #[derive(qemu_api_macros::offsets)] - #[repr(C)] - #[derive(qemu_api_macros::Object)] - pub struct DummyState { - pub _parent: DeviceState, - pub migrate_clock: bool, - } +// Test that macros can compile. +pub static VMSTATE: VMStateDescription = VMStateDescription { + name: c_str!("name").as_ptr(), + unmigratable: true, + ..Zeroable::ZERO +}; + +#[derive(qemu_api_macros::offsets)] +#[repr(C)] +#[derive(qemu_api_macros::Object)] +pub struct DummyState { + parent: DeviceState, + migrate_clock: bool, +} + +qom_isa!(DummyState: Object, DeviceState); + +declare_properties! { + DUMMY_PROPERTIES, + define_property!( + c_str!("migrate-clk"), + DummyState, + migrate_clock, + unsafe { &qdev_prop_bool }, + bool + ), +} + +unsafe impl ObjectType for DummyState { + type Class = <DeviceState as ObjectType>::Class; + const TYPE_NAME: &'static CStr = c_str!("dummy"); +} - #[repr(C)] - pub struct DummyClass { - pub _parent: DeviceClass, +impl ObjectImpl for DummyState { + type ParentType = DeviceState; + const ABSTRACT: bool = false; +} + +impl DeviceImpl for DummyState { + fn properties() -> &'static [Property] { + &DUMMY_PROPERTIES + } + fn vmsd() -> Option<&'static VMStateDescription> { + Some(&VMSTATE) } +} + +fn init_qom() { + static ONCE: BqlCell<bool> = BqlCell::new(false); - declare_properties! { - DUMMY_PROPERTIES, - define_property!( - c_str!("migrate-clk"), - DummyState, - migrate_clock, - unsafe { &qdev_prop_bool }, - bool - ), + cell::bql_start_test(); + if !ONCE.get() { + unsafe { + module_call_init(module_init_type::MODULE_INIT_QOM); + } + ONCE.set(true); } +} - unsafe impl ObjectType for DummyState { - type Class = DummyClass; - const TYPE_NAME: &'static CStr = c_str!("dummy"); +#[test] +/// Create and immediately drop an instance. +fn test_object_new() { + init_qom(); + unsafe { + object_unref(object_new(DummyState::TYPE_NAME.as_ptr()).cast()); } +} - impl ObjectImpl for DummyState { - type ParentType = DeviceState; - const ABSTRACT: bool = false; +#[test] +/// Try invoking a method on an object. +fn test_typename() { + init_qom(); + let p: *mut DummyState = unsafe { object_new(DummyState::TYPE_NAME.as_ptr()).cast() }; + let p_ref: &DummyState = unsafe { &*p }; + assert_eq!(p_ref.typename(), "dummy"); + unsafe { + object_unref(p_ref.as_object_mut_ptr().cast::<c_void>()); } +} - impl DeviceImpl for DummyState { - fn properties() -> &'static [Property] { - &DUMMY_PROPERTIES - } - fn vmsd() -> Option<&'static VMStateDescription> { - Some(&VMSTATE) - } +// a note on all "cast" tests: usually, especially for downcasts the desired +// class would be placed on the right, for example: +// +// let sbd_ref = p.dynamic_cast::<SysBusDevice>(); +// +// Here I am doing the opposite to check that the resulting type is correct. + +#[test] +#[allow(clippy::shadow_unrelated)] +/// Test casts on shared references. +fn test_cast() { + init_qom(); + let p: *mut DummyState = unsafe { object_new(DummyState::TYPE_NAME.as_ptr()).cast() }; + + let p_ref: &DummyState = unsafe { &*p }; + let obj_ref: &Object = p_ref.upcast(); + assert_eq!(addr_of!(*obj_ref), p.cast()); + + let sbd_ref: Option<&SysBusDevice> = obj_ref.dynamic_cast(); + assert!(sbd_ref.is_none()); + + let dev_ref: Option<&DeviceState> = obj_ref.downcast(); + assert_eq!(addr_of!(*dev_ref.unwrap()), p.cast()); + + // SAFETY: the cast is wrong, but the value is only used for comparison + unsafe { + let sbd_ref: &SysBusDevice = obj_ref.unsafe_cast(); + assert_eq!(addr_of!(*sbd_ref), p.cast()); + + object_unref(p_ref.as_object_mut_ptr().cast::<c_void>()); } +} + +#[test] +#[allow(clippy::shadow_unrelated)] +/// Test casts on mutable references. +fn test_cast_mut() { + init_qom(); + let p: *mut DummyState = unsafe { object_new(DummyState::TYPE_NAME.as_ptr()).cast() }; + + let p_ref: &mut DummyState = unsafe { &mut *p }; + let obj_ref: &mut Object = p_ref.upcast_mut(); + assert_eq!(addr_of_mut!(*obj_ref), p.cast()); + + let sbd_ref: Result<&mut SysBusDevice, &mut Object> = obj_ref.dynamic_cast_mut(); + let obj_ref = sbd_ref.unwrap_err(); - impl_device_class!(DummyState); + let dev_ref: Result<&mut DeviceState, &mut Object> = obj_ref.downcast_mut(); + let dev_ref = dev_ref.unwrap(); + assert_eq!(addr_of_mut!(*dev_ref), p.cast()); + // SAFETY: the cast is wrong, but the value is only used for comparison unsafe { - module_call_init(module_init_type::MODULE_INIT_QOM); - object_unref(object_new(DummyState::TYPE_NAME.as_ptr()).cast()); + let sbd_ref: &mut SysBusDevice = obj_ref.unsafe_cast_mut(); + assert_eq!(addr_of_mut!(*sbd_ref), p.cast()); + + object_unref(p_ref.as_object_mut_ptr().cast::<c_void>()); } } |