/*
* This file is derived from src/macros/mod.rs in the Rust libcore, used under
* the Apache License, Version 2.0. The following is the original copyright
* information from the Rust project:
*
* Copyrights in the Rust project are retained by their contributors. No
* copyright assignment is required to contribute to the Rust project.
*
* Some files include explicit copyright notices and/or license notices.
* For full authorship information, see the version control history or
* https://thanks.rust-lang.org
*
* Except as otherwise noted (below and/or in individual files), Rust is
* licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
* <http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// Expects two expressions are equal to each other (using
/// [std::cmp::PartialEq]).
///
/// On failure, this macro will print the values of the expressions with their
/// debug representations and signal the failure to the test framework. The test
/// will continue past the failure.
///
/// Like [`assert!`], this macro has a second form, where a custom
/// error message can be provided.
///
/// # Examples
///
/// ```
/// let a = 3;
/// let b = 1 + 2;
/// expect_eq!(a, b);
///
/// expect_eq!(a, b, "we are testing addition with {} and {}", a, b);
/// ```
#[macro_export]
macro_rules! expect_eq {
($left:expr, $right:expr $(,)?) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = $
crate::__internal_macro_utils::AssertKind::Eq;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::None
);
}
}
}
});
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = $
crate::__internal_macro_utils::AssertKind::Eq;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::Some(core::format_args!($($arg)+))
);
}
}
}
});
}
/// Asserts that two expressions are equal to each other (using
/// [std::cmp::PartialEq]).
///
/// Unlike [`core::assert_eq!`], this macro will not panic, but instead returns
/// early from a test function.
///
/// Like [`assert!`], this macro has a second form, where a custom
/// panic message can be provided.
///
/// # Examples
///
/// ```
/// let a = 3;
/// let b = 1 + 2;
/// assert_eq!(a, b);
///
/// assert_eq!(a, b, "we are testing addition with {} and {}", a, b);
/// ```
#[macro_export]
macro_rules! assert_eq {
($left:expr, $right:expr $(,)?) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = $
crate::__internal_macro_utils::AssertKind::Eq;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::None
);
return;
}
}
}
});
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = $
crate::__internal_macro_utils::AssertKind::Eq;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
}
}
}
});
}
/// Expects that two expressions are not equal to each other (using
/// [std::cmp::PartialEq]).
///
/// On failure, this macro will print the values of the expressions with their
/// debug representations and signal the failure to the test framework. The test
/// will continue past the failure.
///
/// Like [`assert!`], this macro has a second form, where a custom
/// panic message can be provided.
///
/// # Examples
///
/// ```
/// let a = 3;
/// let b = 2;
/// expect_ne!(a, b);
///
/// expect_ne!(a, b, "we are testing that the values are not equal");
/// ```
#[macro_export]
macro_rules! expect_ne {
($left:expr, $right:expr $(,)?) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = $
crate::__internal_macro_utils::AssertKind::Ne;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::None
);
}
}
}
});
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = $
crate::__internal_macro_utils::AssertKind::Ne;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::Some(core::format_args!($($arg)+))
);
}
}
}
});
}
/// Asserts that two expressions are not equal to each other (using
/// [std::cmp::PartialEq]).
///
/// Unlike [`core::assert_ne!`], this macro will not panic, but instead returns
/// early from a test function.
///
/// Like [`assert!`], this macro has a second form, where a custom
/// panic message can be provided.
///
/// # Examples
///
/// ```
/// let a = 3;
/// let b = 2;
/// assert_ne!(a, b);
///
/// assert_ne!(a, b, "we are testing that the values are not equal");
/// ```
#[macro_export]
macro_rules! assert_ne {
($left:expr, $right:expr $(,)?) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = $
crate::__internal_macro_utils::AssertKind::Ne;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::None
);
return;
}
}
}
});
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = $
crate::__internal_macro_utils::AssertKind::Ne;
// The reborrows below are intentional. Without them, the
// stack slot for the borrow is initialized even before the
// values are compared, leading to a noticeable slow down.
$
crate::__internal_macro_utils::assert_failed(
kind,
&*left_val,
&*right_val,
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
}
}
}
});
}
/// Asserts that a `Result` expression is `Ok`
///
/// On failure, this macro will print an error message containing the `Err`
/// value and signal the failure to the test framework. On success, the macro
/// expression will evaluate to the unwrapped `Ok` value.
///
/// Like [`assert!`], this macro has a second form, where a custom error
/// message can be provided with or without arguments for formatting. See
/// [`core::fmt`] for syntax for this form. Expressions used as format arguments
/// will only be evaluated if the assertion fails.
///
/// Failures will include a best-effort representation of the error value in the
/// error message. It will use the [std::fmt::Display], [std::fmt::Debug], or
/// [std::any::type_name] in that order of priority, depending on which ones are
/// implemented for the error type. (This is implemented with
/// [autoderef specialization], so it will work for concrete types, but using it
/// for unconstrained generic `T` will always use the [std::any::type_name]
/// impl, regardless of what traits the type actually implements. Similarly, if
/// the type is declared as `T: Debug`, the [std::fmt::Debug] impl will be
/// invoked, even if the concrete type implements [std::fmt::Display] as well.)
///
/// # Examples
///
/// ```
/// let x: Result<usize, String> = Ok(4);
/// let x: usize = assert_ok!(x);
///
/// let y: Result<usize, String> = Ok(x);
/// assert_ok!(y, "something went wrong; x was {}", x);
/// ```
///
/// [autoderef specialization]: https://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html
#[macro_export]
macro_rules! assert_ok {
($result:expr $(,)?) => ({
match ($result) {
Ok(t) => t,
Err(e) => {
$
crate::__internal_macro_utils::assert_ok_failed(
core::stringify!($result),
$
crate::__internal_macro_utils::display_best_effort!(e),
core::option::Option::None
);
return;
}
}
});
($result:expr, $($arg:tt)+) => ({
match ($result) {
Ok(t) => t,
Err(e) => {
$
crate::__internal_macro_utils::assert_ok_failed(
core::stringify!($result),
$
crate::__internal_macro_utils::display_best_effort!(e),
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
}
}
});
}
/// Asserts that a `Result` expression is `Err`
///
/// On failure, this macro will print an error message containing the `Ok`
/// value and signal the failure to the test framework. On success, the macro
/// expression will evaluate to the unwrapped `Err` value.
///
/// Like [`assert!`], this macro has a second form, where a custom error
/// message can be provided with or without arguments for formatting. See
/// [`core::fmt`] for syntax for this form. Expressions used as format arguments
/// will only be evaluated if the assertion fails.
///
/// Failures will include a best-effort representation of the `Ok` value in the
/// error message. It will use the [std::fmt::Display], [std::fmt::Debug], or
/// [std::any::type_name] in that order of priority, depending on which ones are
/// implemented for the okay type. (This is implemented with
/// [autoderef specialization], so it will work for concrete types, but using it
/// for unconstrained generic `T` will always use the [std::any::type_name]
/// impl, regardless of what traits the type actually implements. Similarly, if
/// the type is declared as `T: Debug`, the [std::fmt::Debug] impl will be
/// invoked, even if the concrete type implements [std::fmt::Display] as well.)
///
/// # Examples
///
/// ```
/// let x: Result<usize, String> = Err(String::from("something wrong"));
/// let x: String = assert_err!(x);
///
/// let y: Result<usize, String> = Err(x.clone());
/// assert_err!(y, "unexpected success; should have gotten Err({})", x);
/// ```
///
/// [autoderef specialization]: https://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html
#[macro_export]
macro_rules! assert_err {
($result:expr $(,)?) => ({
match ($result) {
Ok(t) => {
$
crate::__internal_macro_utils::assert_err_failed(
core::stringify!($result),
$
crate::__internal_macro_utils::display_best_effort!(t),
core::option::Option::None
);
return;
}
Err(e) => e,
}
});
($result:expr, $($arg:tt)+) => ({
match ($result) {
Ok(t) => {
$
crate::__internal_macro_utils::assert_err_failed(
core::stringify!($result),
$
crate::__internal_macro_utils::display_best_effort!(t),
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
}
Err(e) => e,
}
});
}
/// Expects that a boolean expression is `true` at runtime.
///
/// On failure, this macro will print an error message and signal the failure to
/// the test framework. The test will continue past the failure.
///
/// # Custom Messages
///
/// This macro has a second form, where a custom error message can
/// be provided with or without arguments for formatting. See [`core::fmt`]
/// for syntax for this form. Expressions used as format arguments will only
/// be evaluated if the assertion fails.
#[macro_export]
macro_rules! expect {
($cond:expr $(,)?) => ({
match (&($cond)) {
(cond) => {
if (!*cond) {
$
crate::__internal_macro_utils::simple_assert_failed(
core::stringify!($cond),
core::option::Option::None
);
}
}
}
});
($cond:expr, $($arg:tt)+) => ({
match (&($cond)) {
(cond) => {
if (!*cond) {
$
crate::__internal_macro_utils::simple_assert_failed(
core::stringify!($cond),
core::option::Option::Some(core::format_args!($($arg)+))
);
}
}
}
});
}
/// Expects that a value matches the given pattern at runtime.
///
/// On failure, this macro will print an error message and signal the failure to
/// the test framework. The test will continue past the failure.
///
/// # Custom Messages
///
/// This macro has a second form, where a custom error message can
/// be provided with or without arguments for formatting. See [`core::fmt`]
/// for syntax for this form. Expressions used as format arguments will only
/// be evaluated if the assertion fails.
///
/// # Exampples
/// ```
/// use test::expect_matches;
/// let a = Some(15);
/// let b = Some(2112);
///
/// expect_matches!(a, Some(_));
/// expect_matches!(a, Some(x) if x < 100);
/// expect_matches!(b, Some(2000..3000), "Missing or out of range");
///
/// // Fails test:
/// expect_matches!(b, None);
/// expect_matches!(a, Some(16), "Wrong value for {}", "a");
/// ```
#[macro_export]
macro_rules! expect_matches {
($actual:expr, $(|)? $( $pattern:pat_param )|+ $(
if $guard: expr )? $(,)?) => ({
match $actual {
$( $pattern )|+ $(
if $guard )? => {}
actual_val => {
$
crate::__internal_macro_utils::assert_matches_failed(
core::stringify!($actual),
core::stringify!($( $pattern )|+ $(
if $guard )?),
$
crate::__internal_macro_utils::display_best_effort!(actual_val),
core::option::Option::None
);
}
}
});
($actual:expr, $(|)? $( $pattern:pat_param )|+ $(
if $guard: expr )?, $($arg:tt)+) => ({
match $actual {
$( $pattern )|+ $(
if $guard )? => {}
actual_val => {
$
crate::__internal_macro_utils::assert_matches_failed(
core::stringify!($actual),
core::stringify!($( $pattern )|+ $(
if $guard )?),
$
crate::__internal_macro_utils::display_best_effort!(actual_val),
core::option::Option::Some(core::format_args!($($arg)+))
);
}
}
});
}
/// Asserts that a boolean expression is `true` at runtime.
///
/// Unlike [`core::assert!`], this macro will not panic, but instead returns
/// early from a test function.
///
/// # Custom Messages
///
/// This macro has a second form, where a custom error message can
/// be provided with or without arguments for formatting. See [`core::fmt`]
/// for syntax for this form. Expressions used as format arguments will only
/// be evaluated if the assertion fails.
#[macro_export]
macro_rules! assert {
($cond:expr $(,)?) => ({
match (&($cond)) {
(cond) => {
if (!*cond) {
$
crate::__internal_macro_utils::simple_assert_failed(
core::stringify!($cond),
core::option::Option::None
);
return;
}
}
}
});
($cond:expr, $($arg:tt)+) => ({
match (&($cond)) {
(cond) => {
if (!*cond) {
$
crate::__internal_macro_utils::simple_assert_failed(
core::stringify!($cond),
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
}
}
}
});
}
/// Expects that a value matches the given pattern at runtime.
///
/// Unlike [`core::assert_matches::assert_matches!`], this macro will not panic,
/// but instead returns early from a test function.
///
/// # Custom Messages
///
/// This macro has a second form, where a custom error message can
/// be provided with or without arguments for formatting. See [`core::fmt`]
/// for syntax for this form. Expressions used as format arguments will only
/// be evaluated if the assertion fails.
///
/// # Exampples
/// ```
/// use test::assert_matches;
/// let a = Some(15);
/// let b = Some(2112);
///
/// assert_matches!(a, Some(_));
/// assert_matches!(a, Some(x) if x < 100);
/// assert_matches!(b, Some(2000..3000), "Missing or out of range");
///
/// // Fails test and returns early:
/// assert_matches!(b, None);
/// assert_matches!(a, Some(16), "Wrong value for {}", "a");
/// ```
#[macro_export]
macro_rules! assert_matches {
($actual:expr, $(|)? $( $pattern:pat_param )|+ $(
if $guard: expr )? $(,)?) => ({
match $actual {
$( $pattern )|+ $(
if $guard )? => {}
actual_val => {
$
crate::__internal_macro_utils::assert_matches_failed(
core::stringify!($actual),
core::stringify!($( $pattern )|+ $(
if $guard )?),
$
crate::__internal_macro_utils::display_best_effort!(actual_val),
core::option::Option::None
);
return;
}
}
});
($actual:expr, $(|)? $( $pattern:pat_param )|+ $(
if $guard: expr )?, $($arg:tt)+) => ({
match $actual {
$( $pattern )|+ $(
if $guard )? => {}
actual_val => {
$
crate::__internal_macro_utils::assert_matches_failed(
core::stringify!($actual),
core::stringify!($( $pattern )|+ $(
if $guard )?),
$
crate::__internal_macro_utils::display_best_effort!(actual_val),
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
}
}
});
}
/// Fails the test and diverges.
///
/// Unlike [`core::panic!`], this macro will not unwind/abort, but instead returns
/// early from a test function.
///
/// This macro can be used with or without providing a custom error message.
/// Formatting is supported; see [`core::fmt`] for syntax.
#[macro_export]
macro_rules! fail {
() => ({
$
crate::__internal_macro_utils::simple_assert_failed(
"encountered test failure",
core::option::Option::None
);
return;
});
($($arg:tt)+) => ({
$
crate::__internal_macro_utils::simple_assert_failed(
"encountered test failure",
core::option::Option::Some(core::format_args!($($arg)+))
);
return;
});
}
/// Marks the test as skipped.
///
/// This macro can be used with or without providing a custom error message.
/// Formatting is supported; see [`core::fmt`] for syntax.
#[macro_export]
macro_rules! skip {
() => ({
$
crate::skip();
return;
});
($($arg:tt)+) => ({
std::eprintln!(
"test skipped: {}, {}",
core::format_args!($($arg)+),
std::panic::Location::caller()
);
$
crate::skip();
return;
});
}