From: Miguel Ojeda <ojeda@kernel.org>
To: Brendan Higgins <brendan.higgins@linux.dev>,
David Gow <davidgow@google.com>, Miguel Ojeda <ojeda@kernel.org>,
Alex Gaynor <alex.gaynor@gmail.com>
Cc: "Rae Moar" <rmoar@google.com>,
linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
patches@lists.linux.dev
Subject: [PATCH 1/7] rust: kunit: support KUnit-mapped `assert!` macros in `#[test]`s
Date: Fri, 2 May 2025 23:51:26 +0200 [thread overview]
Message-ID: <20250502215133.1923676-2-ojeda@kernel.org> (raw)
In-Reply-To: <20250502215133.1923676-1-ojeda@kernel.org>
The KUnit `#[test]` support that landed recently is very basic and does
not map the `assert*!` macros into KUnit like the doctests do, so they
panic at the moment.
Thus implement the custom mapping in a similar way to doctests, reusing
the infrastructure there.
In Rust 1.88.0, the `file()` method in `Span` may be stable [1]. However,
it was changed recently (from `SourceFile`), so we need to do something
different in previous versions. Thus create a helper for it and use it
to get the path.
With this, a failing test suite like:
#[kunit_tests(my_test_suite)]
mod tests {
use super::*;
#[test]
fn my_first_test() {
assert_eq!(42, 43);
}
#[test]
fn my_second_test() {
assert!(42 >= 43);
}
}
will properly map back to KUnit, printing something like:
[ 1.924325] KTAP version 1
[ 1.924421] # Subtest: my_test_suite
[ 1.924506] # speed: normal
[ 1.924525] 1..2
[ 1.926385] # my_first_test: ASSERTION FAILED at rust/kernel/lib.rs:251
[ 1.926385] Expected 42 == 43 to be true, but is false
[ 1.928026] # my_first_test.speed: normal
[ 1.928075] not ok 1 my_first_test
[ 1.928723] # my_second_test: ASSERTION FAILED at rust/kernel/lib.rs:256
[ 1.928723] Expected 42 >= 43 to be true, but is false
[ 1.929834] # my_second_test.speed: normal
[ 1.929868] not ok 2 my_second_test
[ 1.930032] # my_test_suite: pass:0 fail:2 skip:0 total:2
[ 1.930153] # Totals: pass:0 fail:2 skip:0 total
Link: https://github.com/rust-lang/rust/pull/140514 [1]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
init/Kconfig | 3 +++
rust/Makefile | 3 ++-
rust/kernel/kunit.rs | 1 -
rust/macros/helpers.rs | 16 ++++++++++++++++
rust/macros/kunit.rs | 28 +++++++++++++++++++++++++++-
rust/macros/lib.rs | 4 ++++
6 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/init/Kconfig b/init/Kconfig
index 63f5974b9fa6..5f442c64c47b 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -140,6 +140,9 @@ config LD_CAN_USE_KEEP_IN_OVERLAY
config RUSTC_HAS_COERCE_POINTEE
def_bool RUSTC_VERSION >= 108400
+config RUSTC_HAS_SPAN_FILE
+ def_bool RUSTC_VERSION >= 108800
+
config PAHOLE_VERSION
int
default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE))
diff --git a/rust/Makefile b/rust/Makefile
index 3aca903a7d08..075b38a24997 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -402,7 +402,8 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro \
- --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $<
+ --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) \
+ @$(objtree)/include/generated/rustc_cfg $<
# Procedural macros can only be used with the `rustc` that compiled it.
$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
index 1604fb6a5b1b..2659895d4c5d 100644
--- a/rust/kernel/kunit.rs
+++ b/rust/kernel/kunit.rs
@@ -323,7 +323,6 @@ mod tests {
#[test]
fn rust_test_kunit_example_test() {
- #![expect(clippy::eq_op)]
assert_eq!(1 + 1, 2);
}
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index a3ee27e29a6f..57c3b0f0c194 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -86,3 +86,19 @@ pub(crate) fn function_name(input: TokenStream) -> Option<Ident> {
}
None
}
+
+pub(crate) fn file() -> String {
+ #[cfg(not(CONFIG_RUSTC_HAS_SPAN_FILE))]
+ {
+ proc_macro::Span::call_site()
+ .source_file()
+ .path()
+ .to_string_lossy()
+ .into_owned()
+ }
+
+ #[cfg(CONFIG_RUSTC_HAS_SPAN_FILE)]
+ {
+ proc_macro::Span::call_site().file()
+ }
+}
diff --git a/rust/macros/kunit.rs b/rust/macros/kunit.rs
index 4f553ecf40c0..eb4f2afdbe43 100644
--- a/rust/macros/kunit.rs
+++ b/rust/macros/kunit.rs
@@ -101,6 +101,8 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
// ```
let mut kunit_macros = "".to_owned();
let mut test_cases = "".to_owned();
+ let mut assert_macros = "".to_owned();
+ let path = crate::helpers::file();
for test in &tests {
let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{}", test);
let kunit_wrapper = format!(
@@ -114,6 +116,27 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
test, kunit_wrapper_fn_name
)
.unwrap();
+ writeln!(
+ assert_macros,
+ r#"
+/// Overrides the usual [`assert!`] macro with one that calls KUnit instead.
+#[allow(unused)]
+macro_rules! assert {{
+ ($cond:expr $(,)?) => {{{{
+ kernel::kunit_assert!("{test}", "{path}", 0, $cond);
+ }}}}
+}}
+
+/// Overrides the usual [`assert_eq!`] macro with one that calls KUnit instead.
+#[allow(unused)]
+macro_rules! assert_eq {{
+ ($left:expr, $right:expr $(,)?) => {{{{
+ kernel::kunit_assert_eq!("{test}", "{path}", 0, $left, $right);
+ }}}}
+}}
+ "#
+ )
+ .unwrap();
}
writeln!(kunit_macros).unwrap();
@@ -152,7 +175,10 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
}
}
- let mut new_body = TokenStream::from_iter(new_body);
+ let body = new_body;
+ let mut new_body = TokenStream::new();
+ new_body.extend::<TokenStream>(assert_macros.parse().unwrap());
+ new_body.extend(body);
new_body.extend::<TokenStream>(kunit_macros.parse().unwrap());
tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, new_body)));
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 9acaa68c974e..8bd7906276be 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -6,6 +6,10 @@
// and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is
// touched by Kconfig when the version string from the compiler changes.
+// TODO: check that when Rust 1.88.0 is released, this would be enough:
+// #![cfg_attr(not(CONFIG_RUSTC_HAS_SPAN_FILE), feature(proc_macro_span))]
+#![feature(proc_macro_span)]
+
#[macro_use]
mod quote;
mod concat_idents;
--
2.49.0
next prev parent reply other threads:[~2025-05-02 21:51 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-02 21:51 [PATCH 0/7] Rust KUnit `#[test]` support improvements Miguel Ojeda
2025-05-02 21:51 ` Miguel Ojeda [this message]
2025-05-04 17:41 ` [PATCH 1/7] rust: kunit: support KUnit-mapped `assert!` macros in `#[test]`s Tamir Duberstein
2025-05-27 0:02 ` Miguel Ojeda
2025-05-05 6:02 ` David Gow
2025-05-27 0:08 ` Miguel Ojeda
2025-05-02 21:51 ` [PATCH 2/7] rust: kunit: support checked `-> Result`s in KUnit `#[test]`s Miguel Ojeda
2025-05-04 17:33 ` Tamir Duberstein
2025-05-04 17:59 ` Miguel Ojeda
2025-05-05 6:03 ` David Gow
2025-05-05 6:02 ` David Gow
2025-05-05 19:34 ` Boqun Feng
2025-05-06 6:32 ` David Gow
2025-05-27 15:22 ` Miguel Ojeda
2025-05-02 21:51 ` [PATCH 3/7] rust: add `kunit_tests` to the prelude Miguel Ojeda
2025-05-05 6:02 ` David Gow
2025-05-05 6:02 ` David Gow
2025-05-02 21:51 ` [PATCH 4/7] rust: str: convert `rusttest` tests into KUnit Miguel Ojeda
2025-05-04 17:30 ` Tamir Duberstein
2025-05-04 18:31 ` Miguel Ojeda
2025-05-04 18:39 ` Tamir Duberstein
2025-05-04 19:02 ` Miguel Ojeda
2025-05-05 6:03 ` David Gow
2025-05-05 6:02 ` David Gow
2025-05-10 1:58 ` John Hubbard
2025-05-02 21:51 ` [PATCH 5/7] rust: str: take advantage of the `-> Result` support in KUnit `#[test]`'s Miguel Ojeda
2025-05-04 17:29 ` Tamir Duberstein
2025-05-04 18:15 ` Miguel Ojeda
2025-05-04 18:22 ` Tamir Duberstein
2025-05-04 21:54 ` Miguel Ojeda
2025-05-05 6:03 ` David Gow
2025-05-05 6:02 ` David Gow
2025-05-02 21:51 ` [PATCH 6/7] Documentation: rust: rename `#[test]`s to "`rusttest` host tests" Miguel Ojeda
2025-05-05 6:02 ` David Gow
2025-05-02 21:51 ` [PATCH 7/7] Documentation: rust: testing: add docs on the new KUnit `#[test]` tests Miguel Ojeda
2025-05-05 6:02 ` David Gow
2025-05-05 16:57 ` [PATCH 0/7] Rust KUnit `#[test]` support improvements Danilo Krummrich
2025-05-05 17:07 ` Miguel Ojeda
2025-05-27 0:10 ` Miguel Ojeda
2025-05-27 0:12 ` Miguel Ojeda
2025-05-28 8:03 ` Miguel Ojeda
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250502215133.1923676-2-ojeda@kernel.org \
--to=ojeda@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=brendan.higgins@linux.dev \
--cc=dakr@kernel.org \
--cc=davidgow@google.com \
--cc=gary@garyguo.net \
--cc=kunit-dev@googlegroups.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=rmoar@google.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.