diff --git a/src/core.rs b/src/core.rs index 07beddad..8bdbc81a 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,17 +1,18 @@ //! Basic operations useful for building a testsuite use crate::test_result::Errored; -use bstr::ByteSlice as _; use color_eyre::eyre::Result; use crossbeam_channel::unbounded; use crossbeam_channel::Receiver; use crossbeam_channel::Sender; +use regex::bytes::RegexSet; use std::num::NonZeroUsize; use std::path::Component; use std::path::Path; use std::path::Prefix; use std::process::Command; use std::process::Output; +use std::sync::OnceLock; use std::thread; pub(crate) fn run_command(cmd: &mut Command) -> Result { @@ -53,20 +54,28 @@ pub(crate) fn strip_path_prefix<'a>( impl CrateType { /// Heuristic: - /// * if the file contains `#[test]`, automatically pass `--cfg test`. - /// * if the file does not contain `fn main()` or `#[start]`, automatically pass `--crate-type=lib`. - /// This avoids having to spam `fn main() {}` in almost every test. + /// * [`CrateType::ProcMacro`] if the file contains a [proc macro attribute] + /// * [`CrateType::Test`] if the file contains `#[test]` + /// * [`CrateType::Bin`] if the file contains `fn main()` or `#[start]` + /// * otherwise [`CrateType::Lib`] + /// + /// [proc macro attribute]: https://doc.rust-lang.org/reference/procedural-macros.html pub fn from_file_contents(file_contents: &[u8]) -> CrateType { - if file_contents.find(b"#[proc_macro").is_some() { - CrateType::ProcMacro - } else if file_contents.find(b"#[test]").is_some() { - CrateType::Test - } else if file_contents.find(b"fn main()").is_none() - && file_contents.find(b"#[start]").is_none() - { - CrateType::Lib - } else { - CrateType::Bin + static RE: OnceLock = OnceLock::new(); + let re = RE.get_or_init(|| { + RegexSet::new([ + r"#\[proc_macro(_derive|_attribute)?[\](]", + r"#\[test\]", + r"fn main()|#\[start\]", + ]) + .unwrap() + }); + + match re.matches(file_contents).iter().next() { + Some(0) => CrateType::ProcMacro, + Some(1) => CrateType::Test, + Some(2) => CrateType::Bin, + _ => CrateType::Lib, } } } diff --git a/tests/integrations/basic/Cargo.stdout b/tests/integrations/basic/Cargo.stdout index 55b82b21..3a17343b 100644 --- a/tests/integrations/basic/Cargo.stdout +++ b/tests/integrations/basic/Cargo.stdout @@ -9,6 +9,8 @@ running 3 tests test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished Building dependencies ... ok +Building aux file tests/actual_tests/auxiliary/proc_macro_attr.rs ... ok +tests/actual_tests/aux_attr_proc_macro.rs ... ok Building aux file tests/actual_tests/auxiliary/derive_proc_macro.rs ... ok tests/actual_tests/aux_derive.fixed ... ok tests/actual_tests/aux_derive.rs ... ok @@ -42,7 +44,7 @@ tests/actual_tests/unicode.rs ... ok tests/actual_tests/windows_paths.rs ... ok tests/actual_tests/subdir/aux_proc_macro.rs ... ok -test result: ok. 30 passed; +test result: ok. 31 passed; running 0 tests diff --git a/tests/integrations/basic/tests/actual_tests/aux_attr_proc_macro.rs b/tests/integrations/basic/tests/actual_tests/aux_attr_proc_macro.rs new file mode 100644 index 00000000..7f2b4a51 --- /dev/null +++ b/tests/integrations/basic/tests/actual_tests/aux_attr_proc_macro.rs @@ -0,0 +1,9 @@ +//@aux-build:proc_macro_attr.rs +//@check-pass + +extern crate proc_macro_attr; + +#[proc_macro_attr::passthrough] +pub fn f() {} + +pub fn g() {} diff --git a/tests/integrations/basic/tests/actual_tests/auxiliary/proc_macro_attr.rs b/tests/integrations/basic/tests/actual_tests/auxiliary/proc_macro_attr.rs new file mode 100644 index 00000000..acfcdce4 --- /dev/null +++ b/tests/integrations/basic/tests/actual_tests/auxiliary/proc_macro_attr.rs @@ -0,0 +1,8 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn passthrough(_: TokenStream, item: TokenStream) -> TokenStream { + item +}