Attribute Macro generic_tests::define [−][src]
#[define]
Populates a module tree with test cases parameterizing generic definitions.
This macro is used to annotate a module containing test case definitions.
All functions defined immediately in the module and marked with
a test attribute must have the same number of generic
type parameters. Each function's signature must be as required
by the test attribute that the function is marked with; thus, the functions
marked with test
must have no parameters and their return type must be
either ()
or Result<(), E> where E: std::error::Error
.
Empty submodules defined inline at any depth under the module on which
the macro is invoked can be annotated with the instantiate_tests
attribute. The macro populates these submodules with functions whose names,
signatures, and test attributes mirror the generic test functions at the
macro invocation root module, each calling its generic namesake
parameterized with the arguments given in instantiate_tests
.
Basic example
#[generic_tests::define] mod tests { use std::borrow::Cow; use std::fmt::Display; #[test] fn print<S>() where S: From<&'static str> + Display, { let s = S::from("Hello, world!"); println!("{}", s); } #[instantiate_tests(<String>)] mod string {} #[instantiate_tests(<&'static str>)] mod str_slice {} #[instantiate_tests(<Cow<'static, str>>)] mod cow {} }
Test attributes
The macro checks the paths of function attributes against a customizable
set of attributes that annotate the functions for the test framework.
Only functions with at least one of the attributes found in this set
are selected for instantiation.
These attributes are replicated to the instantiated test case functions and
erased from the original generic definitions. By default, the
test
, bench
, ignore
, and should_panic
attributes get this
treatment. To recognize other test attributes, their paths can be
listed in the attrs()
parameter of the define
attribute. Use of the
attrs()
parameter overrides the default set.
#[generic_tests::define(attrs(tokio::test))] mod async_tests { use bytes::{Buf, Bytes}; use tokio::io::{self, AsyncWriteExt}; #[tokio::test] async fn test_write_buf<T: Buf>() -> io::Result<()> where T: From<&'static str>, { let mut buf = T::from("Hello, world!"); io::sink().write_buf(&mut buf).await?; Ok(()) } #[instantiate_tests(<Bytes>)] mod test_bytes {} }
The copy_attrs()
list specifies attributes that are copied to the
instantiated test case functions and preserved on the generic functions.
By default, this set consists of cfg
, enabling consistent conditional
compilation.
#[generic_tests::define(copy_attrs(cfg, cfg_attr))] mod tests { use super::Foo; #[test] #[cfg(windows)] fn test_only_on_windows<T>() { // ... } #[test] #[cfg_attr(feature = "my-fn-enhancer", bells_and_whistles)] fn test_with_optional_bells_and_whistles<T>() { // ... } #[instantiate_tests(<Foo>)] mod foo {} }
The attribute sets can be customized for an individual generic test
function with the generic_test
attribute.
#[generic_tests::define] mod tests { use super::Foo; #[generic_test(attrs(test, cfg_attr), copy_attrs(allow))] #[test] #[cfg_attr(windows, ignore)] #[allow(dead_code)] fn works_everywhere_except_windows<T>() { // ... } #[instantiate_tests(<Foo>)] mod foo {} }
Finally, any attributes on the generic functions' parameters are always copied verbatim to the instantiated functions.