//! A testing library that makes it easy(ish) to add intentional errors to a program //! //! When testing error-handling codepaths, it is often useful to programmatically tell parts of the //! code to fail. This crate provides the [`failspot!()`][failspot] macro, which can be used //! to mark a spot in the codepath where an intentional failure can be toggled on and off //! from testing code. //! //! Adding it to code is fairly simple: //! //! ```no_run //! # use {failspot::failspot, std::{error::Error, fs, io, path::Path}}; //! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } //! # fn main() { //! # read_data_file("/tmp/foo".as_ref()); //! # } //! fn read_data_file(path: &Path) -> Result<Vec<u8>, Box<dyn Error>> { //! // `FailDataRead` is a variant of an enum that was declared in our crate //! // `bail` returns `Err` and does type conversion on the error type //! failspot!(FailDataRead bail(io::Error::other("failed due to test config"))); //! Ok(fs::read(path)?) //! } //! ``` //! //! The [`failspot_name!()`][failspot_name] macro is used to declare an enum that can be used //! to name a failspot. Its syntax is identical to a regular enum declaration: //! //! ```no_run //! # use failspot::failspot_name; //! failspot_name! { //! pub enum FailSpotName { //! StuffWentWrong, //! } //! } //! ``` //! //! # Syntaxes //! //! The [`failspot!()`][failspot] macro has **four main syntaxes**. Each takes either a //! **long form** or a **short form**. //! //! The **long form** explicitly contains the path to the enum containing the failspot names. This //! is useful if there are multiple enums with different failspot names, or if the enum is only //! accessible at a non-standard name or path. //! //! If the enum can be reached at the name `crate::FailSpotName` (either because it was declared in //! the crate root or re-exported there), the **short form** versions of these macros //! can be used. The examples below make this clear: //! //! ## "if-else" syntax (long form) //! //! Useful when standard if-else behavior is desired: //! //! ``` //! # use {failspot::failspot}; //! # pub mod my_module { //! # failspot::failspot_name! { pub enum MyFailName { FailDataRead } } //! # } //! # fn main() { //! // In "long form", the entire path to the enum must be spelled out //! let _enabled = failspot!(if <crate::my_module::MyFailName>::FailDataRead { //! println!("Data read failure enabled"); //! true //! } else { //! println!("Data read failure disabled"); //! false //! }); //! # } //! ``` //! //! When the `enabled` feature is not on, the compiler will see the second block verbatim. //! //! ### The same code with the short-form //! //! If an enum named `FailSpotName` is reachable at the crate root, like this: //! //! ``` //! # use failspot::failspot_name; //! // lib.rs //! failspot_name! { //! pub enum FailSpotName { //! FailDataRead, //! } //! } //! ``` //! //! The short form can be used, like this: //! //! ``` //! # use failspot::{failspot, failspot_name}; //! # failspot_name! { pub enum FailSpotName { FailDataRead } } //! # fn main() { //! let _enabled = failspot!(if FailDataRead { //! println!("Data read failure enabled"); //! true //! } else { //! println!("Data read failure disabled"); //! false //! }); //! # } //! ``` //! //! ## "quick expression" syntax //! //! Useful when a short block of syntax should be evaluated when the failspot is enabled: //! //! ``` //! # use {failspot::failspot}; //! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } //! # fn main() { //! failspot!(FailDataRead println!("Data read failure enabled")); //! //! // Also good for panicking //! failspot!(FailDataRead panic!()); //! //! // Or for just early returning //! failspot!(FailDataRead return); //! //! // Multiple statements can be run, but use sparingly as things start to get ugly. //! failspot!(FailDataRead println!("Data read failure enabled"); return); //! # } //! ``` //! //! When the `enabled` feature is not on, the macro will evaluate to the empty block, `{}`. //! //! ## "bail" syntax //! //! Useful for returning an `Err` with error-type conversion: //! //! ``` //! # use {failspot::failspot, std::error::Error}; //! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } //! fn main() -> Result<(), Box<dyn Error>> { //! failspot!(FailDataRead bail(std::io::Error::other("Data read failure enabled"))); //! Ok(()) //! } //! ``` //! //! When the `enabled` feature is not on, the macro will evaluate to the empty block, `{}`. //! //! ## "bool" syntax //! //! Useful to just evaluate whether the failspot is enabled or not: //! //! ``` //! # use {failspot::failspot, std::error::Error}; //! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } //! # fn main() { //! # let bytes_to_read = 5; //! let fail_the_read = bytes_to_read > 5000 || failspot!(FailDataRead); //! # } //! ``` //! //! When the `enabled` feature is not on, the macro will evaluate to the token `false`.
/// Declares an enum that can be used as a name for a [failspot] /// /// When feature `enabled` is off, this macro does nothing. /// /// See the [crate-level docs][crate] for details. #[cfg(feature = "enabled")] #[macro_export]
macro_rules! failspot_name {{
$(#[$m:meta])*
$p:vis enum $n:ident {
$(
$(#[$a:meta])*
$k:ident
),+ $(,)*
}
} => {
$crate::flagset::flags! {
$(#[$m])*
$p enum $n: usize {
$(
$(#[$a])*
$k
),+
}
}
$crate::failspot_global!($n);
}}
/// Declares an enum that can be used as a name for a [failspot] /// /// When feature `enabled` is off, this macro does nothing. /// /// See the [crate-level docs][crate] for details. #[cfg(not(feature = "enabled"))] #[macro_export]
macro_rules! failspot_name(($($t: tt)*) => ());
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.