~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/rustdoc_test_builder.rs

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 //! Test builder for `rustdoc`-generated tests.
  4 //!
  5 //! This script is a hack to extract the test from `rustdoc`'s output. Ideally, `rustdoc` would
  6 //! have an option to generate this information instead, e.g. as JSON output.
  7 //!
  8 //! The `rustdoc`-generated test names look like `{file}_{line}_{number}`, e.g.
  9 //! `...path_rust_kernel_sync_arc_rs_42_0`. `number` is the "test number", needed in cases like
 10 //! a macro that expands into items with doctests is invoked several times within the same line.
 11 //!
 12 //! However, since these names are used for bisection in CI, the line number makes it not stable
 13 //! at all. In the future, we would like `rustdoc` to give us the Rust item path associated with
 14 //! the test, plus a "test number" (for cases with several examples per item) and generate a name
 15 //! from that. For the moment, we generate ourselves a new name, `{file}_{number}` instead, in
 16 //! the `gen` script (done there since we need to be aware of all the tests in a given file).
 17 
 18 use std::io::Read;
 19 
 20 fn main() {
 21     let mut stdin = std::io::stdin().lock();
 22     let mut body = String::new();
 23     stdin.read_to_string(&mut body).unwrap();
 24 
 25     // Find the generated function name looking for the inner function inside `main()`.
 26     //
 27     // The line we are looking for looks like one of the following:
 28     //
 29     // ```
 30     // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_28_0() {
 31     // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_37_0() -> Result<(), impl core::fmt::Debug> {
 32     // ```
 33     //
 34     // It should be unlikely that doctest code matches such lines (when code is formatted properly).
 35     let rustdoc_function_name = body
 36         .lines()
 37         .find_map(|line| {
 38             Some(
 39                 line.split_once("fn main() {")?
 40                     .1
 41                     .split_once("fn ")?
 42                     .1
 43                     .split_once("()")?
 44                     .0,
 45             )
 46             .filter(|x| x.chars().all(|c| c.is_alphanumeric() || c == '_'))
 47         })
 48         .expect("No test function found in `rustdoc`'s output.");
 49 
 50     // Qualify `Result` to avoid the collision with our own `Result` coming from the prelude.
 51     let body = body.replace(
 52         &format!("{rustdoc_function_name}() -> Result<(), impl core::fmt::Debug> {{"),
 53         &format!("{rustdoc_function_name}() -> core::result::Result<(), impl core::fmt::Debug> {{"),
 54     );
 55 
 56     // For tests that get generated with `Result`, like above, `rustdoc` generates an `unwrap()` on
 57     // the return value to check there were no returned errors. Instead, we use our assert macro
 58     // since we want to just fail the test, not panic the kernel.
 59     //
 60     // We save the result in a variable so that the failed assertion message looks nicer.
 61     let body = body.replace(
 62         &format!("}} {rustdoc_function_name}().unwrap() }}"),
 63         &format!("}} let test_return_value = {rustdoc_function_name}(); assert!(test_return_value.is_ok()); }}"),
 64     );
 65 
 66     // Figure out a smaller test name based on the generated function name.
 67     let name = rustdoc_function_name.split_once("_rust_kernel_").unwrap().1;
 68 
 69     let path = format!("rust/test/doctests/kernel/{name}");
 70 
 71     std::fs::write(path, body.as_bytes()).unwrap();
 72 }

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php