mirror of
https://github.com/torvalds/linux.git
synced 2025-04-12 06:49:52 +00:00
rust: kunit: add KUnit case and suite macros
Add a couple of Rust const functions and macros to allow to develop KUnit tests without relying on generated C code: - The `kunit_unsafe_test_suite!` Rust macro is similar to the `kunit_test_suite` C macro. It requires a NULL-terminated array of test cases (see below). - The `kunit_case` Rust function is similar to the `KUNIT_CASE` C macro. It generates as case from the name and function. - The `kunit_case_null` Rust function generates a NULL test case, which is to be used as delimiter in `kunit_test_suite!`. While these functions and macros can be used on their own, a future patch will introduce another macro to create KUnit tests using a user-space like syntax. Signed-off-by: José Expósito <jose.exposito89@gmail.com> Co-developed-by: Matt Gilbride <mattgilbride@google.com> Signed-off-by: Matt Gilbride <mattgilbride@google.com> Co-developed-by: Miguel Ojeda <ojeda@kernel.org> Signed-off-by: Miguel Ojeda <ojeda@kernel.org> Co-developed-by: David Gow <davidgow@google.com> Signed-off-by: David Gow <davidgow@google.com> Link: https://lore.kernel.org/r/20250307090103.918788-2-davidgow@google.com [ Applied Markdown in comment. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
fb625227d5
commit
22097b966f
@ -161,3 +161,127 @@ macro_rules! kunit_assert_eq {
|
||||
$crate::kunit_assert!($name, $file, $diff, $left == $right);
|
||||
}};
|
||||
}
|
||||
|
||||
/// Represents an individual test case.
|
||||
///
|
||||
/// The [`kunit_unsafe_test_suite!`] macro expects a NULL-terminated list of valid test cases.
|
||||
/// Use [`kunit_case_null`] to generate such a delimiter.
|
||||
#[doc(hidden)]
|
||||
pub const fn kunit_case(
|
||||
name: &'static kernel::str::CStr,
|
||||
run_case: unsafe extern "C" fn(*mut kernel::bindings::kunit),
|
||||
) -> kernel::bindings::kunit_case {
|
||||
kernel::bindings::kunit_case {
|
||||
run_case: Some(run_case),
|
||||
name: name.as_char_ptr(),
|
||||
attr: kernel::bindings::kunit_attributes {
|
||||
speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||
},
|
||||
generate_params: None,
|
||||
status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
|
||||
module_name: core::ptr::null_mut(),
|
||||
log: core::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the NULL test case delimiter.
|
||||
///
|
||||
/// The [`kunit_unsafe_test_suite!`] macro expects a NULL-terminated list of test cases. This
|
||||
/// function returns such a delimiter.
|
||||
#[doc(hidden)]
|
||||
pub const fn kunit_case_null() -> kernel::bindings::kunit_case {
|
||||
kernel::bindings::kunit_case {
|
||||
run_case: None,
|
||||
name: core::ptr::null_mut(),
|
||||
generate_params: None,
|
||||
attr: kernel::bindings::kunit_attributes {
|
||||
speed: kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||
},
|
||||
status: kernel::bindings::kunit_status_KUNIT_SUCCESS,
|
||||
module_name: core::ptr::null_mut(),
|
||||
log: core::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a KUnit test suite.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `test_cases` must be a NULL terminated array of valid test cases,
|
||||
/// whose lifetime is at least that of the test suite (i.e., static).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// extern "C" fn test_fn(_test: *mut kernel::bindings::kunit) {
|
||||
/// let actual = 1 + 1;
|
||||
/// let expected = 2;
|
||||
/// assert_eq!(actual, expected);
|
||||
/// }
|
||||
///
|
||||
/// static mut KUNIT_TEST_CASES: [kernel::bindings::kunit_case; 2] = [
|
||||
/// kernel::kunit::kunit_case(kernel::c_str!("name"), test_fn),
|
||||
/// kernel::kunit::kunit_case_null(),
|
||||
/// ];
|
||||
/// kernel::kunit_unsafe_test_suite!(suite_name, KUNIT_TEST_CASES);
|
||||
/// ```
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! kunit_unsafe_test_suite {
|
||||
($name:ident, $test_cases:ident) => {
|
||||
const _: () = {
|
||||
const KUNIT_TEST_SUITE_NAME: [::kernel::ffi::c_char; 256] = {
|
||||
let name_u8 = ::core::stringify!($name).as_bytes();
|
||||
let mut ret = [0; 256];
|
||||
|
||||
if name_u8.len() > 255 {
|
||||
panic!(concat!(
|
||||
"The test suite name `",
|
||||
::core::stringify!($name),
|
||||
"` exceeds the maximum length of 255 bytes."
|
||||
));
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < name_u8.len() {
|
||||
ret[i] = name_u8[i] as ::kernel::ffi::c_char;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ret
|
||||
};
|
||||
|
||||
static mut KUNIT_TEST_SUITE: ::kernel::bindings::kunit_suite =
|
||||
::kernel::bindings::kunit_suite {
|
||||
name: KUNIT_TEST_SUITE_NAME,
|
||||
#[allow(unused_unsafe)]
|
||||
// SAFETY: `$test_cases` is passed in by the user, and
|
||||
// (as documented) must be valid for the lifetime of
|
||||
// the suite (i.e., static).
|
||||
test_cases: unsafe {
|
||||
::core::ptr::addr_of_mut!($test_cases)
|
||||
.cast::<::kernel::bindings::kunit_case>()
|
||||
},
|
||||
suite_init: None,
|
||||
suite_exit: None,
|
||||
init: None,
|
||||
exit: None,
|
||||
attr: ::kernel::bindings::kunit_attributes {
|
||||
speed: ::kernel::bindings::kunit_speed_KUNIT_SPEED_NORMAL,
|
||||
},
|
||||
status_comment: [0; 256usize],
|
||||
debugfs: ::core::ptr::null_mut(),
|
||||
log: ::core::ptr::null_mut(),
|
||||
suite_init_err: 0,
|
||||
is_init: false,
|
||||
};
|
||||
|
||||
#[used]
|
||||
#[allow(unused_unsafe)]
|
||||
#[cfg_attr(not(target_os = "macos"), link_section = ".kunit_test_suites")]
|
||||
static mut KUNIT_TEST_SUITE_ENTRY: *const ::kernel::bindings::kunit_suite =
|
||||
// SAFETY: `KUNIT_TEST_SUITE` is static.
|
||||
unsafe { ::core::ptr::addr_of_mut!(KUNIT_TEST_SUITE) };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user