|
5 | 5 | //! Copyright (c) 2023 José Expósito <jose.exposito89@gmail.com> |
6 | 6 |
|
7 | 7 | use proc_macro::{Delimiter, Group, TokenStream, TokenTree}; |
| 8 | +use std::collections::HashMap; |
8 | 9 | use std::fmt::Write; |
9 | 10 |
|
10 | 11 | pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream { |
@@ -41,20 +42,32 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream { |
41 | 42 | // Get the functions set as tests. Search for `[test]` -> `fn`. |
42 | 43 | let mut body_it = body.stream().into_iter(); |
43 | 44 | let mut tests = Vec::new(); |
| 45 | + let mut attributes: HashMap<String, TokenStream> = HashMap::new(); |
44 | 46 | while let Some(token) = body_it.next() { |
45 | 47 | match token { |
46 | | - TokenTree::Group(ident) if ident.to_string() == "[test]" => match body_it.next() { |
47 | | - Some(TokenTree::Ident(ident)) if ident.to_string() == "fn" => { |
48 | | - let test_name = match body_it.next() { |
49 | | - Some(TokenTree::Ident(ident)) => ident.to_string(), |
50 | | - _ => continue, |
51 | | - }; |
52 | | - tests.push(test_name); |
| 48 | + TokenTree::Punct(ref p) if p.as_char() == '#' => match body_it.next() { |
| 49 | + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => { |
| 50 | + if let Some(TokenTree::Ident(name)) = g.stream().into_iter().next() { |
| 51 | + // Collect attributes because we need to find which are tests. We also |
| 52 | + // need to copy `cfg` attributes so tests can be conditionally enabled. |
| 53 | + attributes |
| 54 | + .entry(name.to_string()) |
| 55 | + .or_default() |
| 56 | + .extend([token, TokenTree::Group(g)]); |
| 57 | + } |
| 58 | + continue; |
53 | 59 | } |
54 | | - _ => continue, |
| 60 | + _ => (), |
55 | 61 | }, |
| 62 | + TokenTree::Ident(i) if i.to_string() == "fn" && attributes.contains_key("test") => { |
| 63 | + if let Some(TokenTree::Ident(test_name)) = body_it.next() { |
| 64 | + tests.push((test_name, attributes.remove("cfg").unwrap_or_default())) |
| 65 | + } |
| 66 | + } |
| 67 | + |
56 | 68 | _ => (), |
57 | 69 | } |
| 70 | + attributes.clear(); |
58 | 71 | } |
59 | 72 |
|
60 | 73 | // Add `#[cfg(CONFIG_KUNIT="y")]` before the module declaration. |
@@ -100,11 +113,22 @@ pub(crate) fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream { |
100 | 113 | let mut test_cases = "".to_owned(); |
101 | 114 | let mut assert_macros = "".to_owned(); |
102 | 115 | let path = crate::helpers::file(); |
103 | | - for test in &tests { |
| 116 | + let num_tests = tests.len(); |
| 117 | + for (test, cfg_attr) in tests { |
104 | 118 | let kunit_wrapper_fn_name = format!("kunit_rust_wrapper_{test}"); |
105 | | - // An extra `use` is used here to reduce the length of the message. |
| 119 | + // Append any `cfg` attributes the user might have written on their tests so we don't |
| 120 | + // attempt to call them when they are `cfg`'d out. An extra `use` is used here to reduce |
| 121 | + // the length of the assert message. |
106 | 122 | let kunit_wrapper = format!( |
107 | | - "unsafe extern \"C\" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit) {{ use ::kernel::kunit::is_test_result_ok; assert!(is_test_result_ok({test}())); }}", |
| 123 | + r#"unsafe extern "C" fn {kunit_wrapper_fn_name}(_test: *mut ::kernel::bindings::kunit) |
| 124 | + {{ |
| 125 | + (*_test).status = ::kernel::bindings::kunit_status_KUNIT_SKIPPED; |
| 126 | + {cfg_attr} {{ |
| 127 | + (*_test).status = ::kernel::bindings::kunit_status_KUNIT_SUCCESS; |
| 128 | + use ::kernel::kunit::is_test_result_ok; |
| 129 | + assert!(is_test_result_ok({test}())); |
| 130 | + }} |
| 131 | + }}"#, |
108 | 132 | ); |
109 | 133 | writeln!(kunit_macros, "{kunit_wrapper}").unwrap(); |
110 | 134 | writeln!( |
@@ -139,7 +163,7 @@ macro_rules! assert_eq {{ |
139 | 163 | writeln!( |
140 | 164 | kunit_macros, |
141 | 165 | "static mut TEST_CASES: [::kernel::bindings::kunit_case; {}] = [\n{test_cases} ::kernel::kunit::kunit_case_null(),\n];", |
142 | | - tests.len() + 1 |
| 166 | + num_tests + 1 |
143 | 167 | ) |
144 | 168 | .unwrap(); |
145 | 169 |
|
|
0 commit comments