mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	Starting with upstream Rust commit a5e3a3f9b6bd ("move
`manual_c_str_literals` to complexity"), to be released in Rust 1.83.0
[1], Clippy now warns on `manual_c_str_literals` by default, e.g.:
    error: manually constructing a nul-terminated string
      --> rust/kernel/kunit.rs:21:13
       |
    21 |             b"\x013%pA\0".as_ptr() as _,
       |             ^^^^^^^^^^^^^ help: use a `c""` literal: `c"\x013%pA"`
       |
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals
       = note: `-D clippy::manual-c-str-literals` implied by `-D warnings`
       = help: to override `-D warnings` add `#[allow(clippy::manual_c_str_literals)]`
Apply the suggestion to clean up the warnings.
Link: https://github.com/rust-lang/rust-clippy/pull/13263 [1]
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/r/20240927164414.560906-1-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
		
	
			
		
			
				
	
	
		
			163 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
 | 
						|
//! KUnit-based macros for Rust unit tests.
 | 
						|
//!
 | 
						|
//! C header: [`include/kunit/test.h`](srctree/include/kunit/test.h)
 | 
						|
//!
 | 
						|
//! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html>
 | 
						|
 | 
						|
use core::{ffi::c_void, fmt};
 | 
						|
 | 
						|
/// Prints a KUnit error-level message.
 | 
						|
///
 | 
						|
/// Public but hidden since it should only be used from KUnit generated code.
 | 
						|
#[doc(hidden)]
 | 
						|
pub fn err(args: fmt::Arguments<'_>) {
 | 
						|
    // SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
 | 
						|
    // are passing.
 | 
						|
    #[cfg(CONFIG_PRINTK)]
 | 
						|
    unsafe {
 | 
						|
        bindings::_printk(
 | 
						|
            c"\x013%pA".as_ptr() as _,
 | 
						|
            &args as *const _ as *const c_void,
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Prints a KUnit info-level message.
 | 
						|
///
 | 
						|
/// Public but hidden since it should only be used from KUnit generated code.
 | 
						|
#[doc(hidden)]
 | 
						|
pub fn info(args: fmt::Arguments<'_>) {
 | 
						|
    // SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
 | 
						|
    // are passing.
 | 
						|
    #[cfg(CONFIG_PRINTK)]
 | 
						|
    unsafe {
 | 
						|
        bindings::_printk(
 | 
						|
            c"\x016%pA".as_ptr() as _,
 | 
						|
            &args as *const _ as *const c_void,
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Asserts that a boolean expression is `true` at runtime.
 | 
						|
///
 | 
						|
/// Public but hidden since it should only be used from generated tests.
 | 
						|
///
 | 
						|
/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
 | 
						|
/// facilities. See [`assert!`] for more details.
 | 
						|
#[doc(hidden)]
 | 
						|
#[macro_export]
 | 
						|
macro_rules! kunit_assert {
 | 
						|
    ($name:literal, $file:literal, $diff:expr, $condition:expr $(,)?) => {
 | 
						|
        'out: {
 | 
						|
            // Do nothing if the condition is `true`.
 | 
						|
            if $condition {
 | 
						|
                break 'out;
 | 
						|
            }
 | 
						|
 | 
						|
            static FILE: &'static $crate::str::CStr = $crate::c_str!($file);
 | 
						|
            static LINE: i32 = core::line!() as i32 - $diff;
 | 
						|
            static CONDITION: &'static $crate::str::CStr = $crate::c_str!(stringify!($condition));
 | 
						|
 | 
						|
            // SAFETY: FFI call without safety requirements.
 | 
						|
            let kunit_test = unsafe { $crate::bindings::kunit_get_current_test() };
 | 
						|
            if kunit_test.is_null() {
 | 
						|
                // The assertion failed but this task is not running a KUnit test, so we cannot call
 | 
						|
                // KUnit, but at least print an error to the kernel log. This may happen if this
 | 
						|
                // macro is called from an spawned thread in a test (see
 | 
						|
                // `scripts/rustdoc_test_gen.rs`) or if some non-test code calls this macro by
 | 
						|
                // mistake (it is hidden to prevent that).
 | 
						|
                //
 | 
						|
                // This mimics KUnit's failed assertion format.
 | 
						|
                $crate::kunit::err(format_args!(
 | 
						|
                    "    # {}: ASSERTION FAILED at {FILE}:{LINE}\n",
 | 
						|
                    $name
 | 
						|
                ));
 | 
						|
                $crate::kunit::err(format_args!(
 | 
						|
                    "    Expected {CONDITION} to be true, but is false\n"
 | 
						|
                ));
 | 
						|
                $crate::kunit::err(format_args!(
 | 
						|
                    "    Failure not reported to KUnit since this is a non-KUnit task\n"
 | 
						|
                ));
 | 
						|
                break 'out;
 | 
						|
            }
 | 
						|
 | 
						|
            #[repr(transparent)]
 | 
						|
            struct Location($crate::bindings::kunit_loc);
 | 
						|
 | 
						|
            #[repr(transparent)]
 | 
						|
            struct UnaryAssert($crate::bindings::kunit_unary_assert);
 | 
						|
 | 
						|
            // SAFETY: There is only a static instance and in that one the pointer field points to
 | 
						|
            // an immutable C string.
 | 
						|
            unsafe impl Sync for Location {}
 | 
						|
 | 
						|
            // SAFETY: There is only a static instance and in that one the pointer field points to
 | 
						|
            // an immutable C string.
 | 
						|
            unsafe impl Sync for UnaryAssert {}
 | 
						|
 | 
						|
            static LOCATION: Location = Location($crate::bindings::kunit_loc {
 | 
						|
                file: FILE.as_char_ptr(),
 | 
						|
                line: LINE,
 | 
						|
            });
 | 
						|
            static ASSERTION: UnaryAssert = UnaryAssert($crate::bindings::kunit_unary_assert {
 | 
						|
                assert: $crate::bindings::kunit_assert {},
 | 
						|
                condition: CONDITION.as_char_ptr(),
 | 
						|
                expected_true: true,
 | 
						|
            });
 | 
						|
 | 
						|
            // SAFETY:
 | 
						|
            //   - FFI call.
 | 
						|
            //   - The `kunit_test` pointer is valid because we got it from
 | 
						|
            //     `kunit_get_current_test()` and it was not null. This means we are in a KUnit
 | 
						|
            //     test, and that the pointer can be passed to KUnit functions and assertions.
 | 
						|
            //   - The string pointers (`file` and `condition` above) point to null-terminated
 | 
						|
            //     strings since they are `CStr`s.
 | 
						|
            //   - The function pointer (`format`) points to the proper function.
 | 
						|
            //   - The pointers passed will remain valid since they point to `static`s.
 | 
						|
            //   - The format string is allowed to be null.
 | 
						|
            //   - There are, however, problems with this: first of all, this will end up stopping
 | 
						|
            //     the thread, without running destructors. While that is problematic in itself,
 | 
						|
            //     it is considered UB to have what is effectively a forced foreign unwind
 | 
						|
            //     with `extern "C"` ABI. One could observe the stack that is now gone from
 | 
						|
            //     another thread. We should avoid pinning stack variables to prevent library UB,
 | 
						|
            //     too. For the moment, given that test failures are reported immediately before the
 | 
						|
            //     next test runs, that test failures should be fixed and that KUnit is explicitly
 | 
						|
            //     documented as not suitable for production environments, we feel it is reasonable.
 | 
						|
            unsafe {
 | 
						|
                $crate::bindings::__kunit_do_failed_assertion(
 | 
						|
                    kunit_test,
 | 
						|
                    core::ptr::addr_of!(LOCATION.0),
 | 
						|
                    $crate::bindings::kunit_assert_type_KUNIT_ASSERTION,
 | 
						|
                    core::ptr::addr_of!(ASSERTION.0.assert),
 | 
						|
                    Some($crate::bindings::kunit_unary_assert_format),
 | 
						|
                    core::ptr::null(),
 | 
						|
                );
 | 
						|
            }
 | 
						|
 | 
						|
            // SAFETY: FFI call; the `test` pointer is valid because this hidden macro should only
 | 
						|
            // be called by the generated documentation tests which forward the test pointer given
 | 
						|
            // by KUnit.
 | 
						|
            unsafe {
 | 
						|
                $crate::bindings::__kunit_abort(kunit_test);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
 | 
						|
///
 | 
						|
/// Public but hidden since it should only be used from generated tests.
 | 
						|
///
 | 
						|
/// Unlike the one in `core`, this one does not panic; instead, it is mapped to the KUnit
 | 
						|
/// facilities. See [`assert!`] for more details.
 | 
						|
#[doc(hidden)]
 | 
						|
#[macro_export]
 | 
						|
macro_rules! kunit_assert_eq {
 | 
						|
    ($name:literal, $file:literal, $diff:expr, $left:expr, $right:expr $(,)?) => {{
 | 
						|
        // For the moment, we just forward to the expression assert because, for binary asserts,
 | 
						|
        // KUnit supports only a few types (e.g. integers).
 | 
						|
        $crate::kunit_assert!($name, $file, $diff, $left == $right);
 | 
						|
    }};
 | 
						|
}
 |