Skip to content

Commit

Permalink
Add assert_result_ok_eq and assert_result_ok_ne
Browse files Browse the repository at this point in the history
  • Loading branch information
joelparkerhenderson committed Sep 11, 2024
1 parent c168f8e commit dcba568
Show file tree
Hide file tree
Showing 7 changed files with 498 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "assertables"
version = "8.3.0"
version = "8.4.0"
authors = ["Joel Parker Henderson <[email protected]>"]
edition = "2021"
description = "Assertables: Rust crate of macros `assert…!` for better tests, quality assurance, debug testing, and runtime reliability."
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Examples:

8.5: Add `assert_option_some_eq`, `assert_option_some_ne` (planned)

8.4: Add `assert_result_ok_eq`, `assert_result_ok_ne` (planned)
8.4: Add `assert_result_ok_eq`, `assert_result_ok_ne`

8.3: Add `assert_poll_ready`, `assert_poll_pending`.

Expand All @@ -229,6 +229,6 @@ Examples:
* Package: assertables-rust-crate
* Version: 8.4.0
* Created: 2021-03-30T15:47:49Z
* Updated: 2024-09-07T22:22:42Z
* Updated: 2024-09-11T02:11:16Z
* License: MIT or Apache-2.0 or GPL-2.0 or GPL-3.0 or contact us for more
* Contact: Joel Parker Henderson ([email protected])
4 changes: 2 additions & 2 deletions help/comparisons/claims/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ If there's an assertion from any of those crates that you would like us to add t
| Contains | [`assert_contains`](https://docs.rs/assertables/latest/assertables/assert_contains) <br> [`assert_not_contains`](https://docs.rs/assertables/latest/assertables/assert_not_contains) | - <br> - |
| Starts/Ends | [`assert_starts_with`](https://docs.rs/assertables/latest/assertables/assert_starts_with) <br> [`assert_not_starts_with`](https://docs.rs/assertables/latest/assertables/assert_not_starts_with) <br> [`assert_ends_with`](https://docs.rs/assertables/latest/assertables/assert_ends_with) <br> [`assert_not_ends_with`](https://docs.rs/assertables/latest/assertables/assert_not_ends_with) | - <br> - <br> - <br> - |
| Result | [`assert_result_ok`](https://docs.rs/assertables/latest/assertables/assert_result/assert_result_ok) <br> [`assert_result_ok_eq`](https://docs.rs/assertables/latest/assertables/assert_result/assert_result_ok_eq) <br> [`assert_result_err`](https://docs.rs/assertables/latest/assertables/assert_result/assert_result_err) | `assert_result_ok` <br> `assert_result_ok_eq` <br> `assert_result_err` |
| Option | [`assert_option_some`](https://docs.rs/assertables/latest/assertables/assert_option/assert_option_some) <br> [`assert_option_some_eq`](https://docs.rs/assertables/latest/assertables/assert_option/assert_option_some_eq) <br> [`assert_option_none`](https://docs.rs/assertables/latest/assertables/assert_option/assert_option_none) | `assert_option_some` <br> `assert_option_some_eq` <br> `assert_option_none` |
| Poll | [`assert_poll_ready`](https://docs.rs/assertables/latest/assertables/assert_poll/assert_poll_ready) <br> [`assert_poll_ready_eq`](https://docs.rs/assertables/latest/assertables/assert_poll/assert_poll_ready_eq) <br> `todo` <br> `todo` <br> [`assert_poll_pending`](https://docs.rs/assertables/latest/assertables/assert_poll/assert_poll_pending) | `assert_ready` <br> `assert_ready_eq` <br> `assert_ready_ok` <br> `assert_ready_err` <br> `assert_pending` |
| Option | [`assert_option_some`](https://docs.rs/assertables/latest/assertables/assert_option/assert_option_some) <br> [`assert_option_some_eq`](https://docs.rs/assertables/latest/assertables/assert_option/assert_option_some_eq) <br> [`assert_option_none`](https://docs.rs/assertables/latest/assertables/assert_option/assert_option_none) | `assert_option_some` <br> `assert_option_some_eq` (planned)<br> `assert_option_none` |
| Poll | [`assert_poll_ready`](https://docs.rs/assertables/latest/assertables/assert_poll/assert_poll_ready) <br> [`assert_poll_ready_eq`](https://docs.rs/assertables/latest/assertables/assert_poll/assert_poll_ready_eq) <br> `todo` <br> `todo` <br> [`assert_poll_pending`](https://docs.rs/assertables/latest/assertables/assert_poll/assert_poll_pending) | `assert_ready` <br> `assert_ready_eq` (planned) <br> `assert_ready_ok` (planned) <br> `assert_ready_err` (planned) <br> `assert_pending` |
| Readers | [`assert_fs_read_to_string_*`](https://docs.rs/assertables/latest/assertables/assert_fs_read_to_string) <br> [`assert_io_read_to_string_*`](https://docs.rs/assertables/latest/assertables/assert_io_read_to_string) | - <br> - |
| Commands | [`assert_command_*`](https://docs.rs/assertables/latest/assertables/assert_command) <br> [`assert_program_args_*`](https://docs.rs/assertables/latest/assertables/assert_program_args) | - <br> - |
| Collections | [`assert_set_*`](https://docs.rs/assertables/latest/assertables/assert_set) <br> [`assert_bag_*`](https://docs.rs/assertables/latest/assertables/assert_bag) | - <br> - |
Expand Down
245 changes: 245 additions & 0 deletions src/assert_result/assert_result_ok_eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
//! Assert expression is ok, and its value is equal to another.
//!
//! # Example
//!
//! ```rust
//! # #[macro_use] extern crate assertables;
//! # fn main() {
//! let a: Result<i8, i8> = Result::Ok(1);
//! let b: Result<i8, i8> = Result::Ok(1);
//! assert_result_ok_eq!(a, b);
//! # }
//! ```
//!
//! # Module macros
//!
//! * [`assert_result_ok_eq`](macro@crate::assert_result_ok_eq)
//! * [`assert_result_ok_eq_as_result`](macro@crate::assert_result_ok_eq_as_result)
//! * [`debug_assert_result_ok_eq`](macro@crate::debug_assert_result_ok_eq)
/// Assert expression is ok, and its value is equal to another.
///
/// * If true, return Result `Ok(())`.
///
/// * Otherwise, return Result `Err` with a diagnostic message.
///
/// This macro provides the same statements as [`assert_result_ok_eq`](macro.assert_result_ok_eq.html),
/// except this macro returns a Result, rather than doing a panic.
///
/// This macro is useful for runtime checks, such as checking parameters,
/// or sanitizing inputs, or handling different results in different ways.
///
/// # Module macros
///
/// * [`assert_result_ok_eq`](macro@crate::assert_result_ok_eq)
/// * [`assert_result_ok_eq_as_result`](macro@crate::assert_result_ok_eq_as_result)
/// * [`debug_assert_result_ok_eq`](macro@crate::debug_assert_result_ok_eq)
///
#[macro_export]
macro_rules! assert_result_ok_eq_as_result {
($a_result:expr, $b_result:expr $(,)?) => {{
match (&$a_result, &$b_result) {
(a_result, b_result) => {
if a_result.is_err() || b_result.is_err() {
Err(format!(
concat!(
"assertion failed: `assert_result_ok_eq!(a, b)`\n",
" a label: `{}`,\n",
" a debug: `{:?}`,\n",
" b label: `{}`,\n",
" b debug: `{:?}`",
),
stringify!($a_result),
$a_result,
stringify!($b_result),
$b_result,
))
} else {
let a_ok = a_result.unwrap();
let b_ok = b_result.unwrap();
if a_ok == b_ok {
Ok(())
} else {
Err(format!(
concat!(
"assertion failed: `assert_result_ok_eq!(a, b)`\n",
" a label: `{}`,\n",
" a debug: `{:?}`,\n",
" b label: `{}`,\n",
" b debug: `{:?}`,\n",
" a ok: `{:?}`,\n",
" b ok: `{:?}`"
),
stringify!($a_result),
$a_result,
stringify!($b_result),
$b_result,
a_ok,
b_ok
))
}
}
}
}
}};
}

#[cfg(test)]
mod tests {

#[test]
fn test_assert_result_ok_eq_as_result_x_success() {
let a: Result<i8, i8> = Result::Ok(1);
let b: Result<i8, i8> = Result::Ok(1);
let result = assert_result_ok_eq_as_result!(a, b);
assert_eq!(result, Ok(()));
}

#[test]
fn test_assert_result_ok_eq_as_result_x_failure_because_ok_ne() {
let a: Result<i8, i8> = Result::Ok(1);
let b: Result<i8, i8> = Result::Ok(2);
let result = assert_result_ok_eq_as_result!(a, b);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
concat!(
"assertion failed: `assert_result_ok_eq!(a, b)`\n",
" a label: `a`,\n",
" a debug: `Ok(1)`,\n",
" b label: `b`,\n",
" b debug: `Ok(2)`,\n",
" a ok: `1`,\n",
" b ok: `2`",
)
);
}

#[test]
fn test_assert_result_ok_eq_as_result_x_failure_because_err() {
let a: Result<i8, i8> = Result::Ok(1);
let b: Result<i8, i8> = Result::Err(1);
let result = assert_result_ok_eq_as_result!(a, b);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
concat!(
"assertion failed: `assert_result_ok_eq!(a, b)`\n",
" a label: `a`,\n",
" a debug: `Ok(1)`,\n",
" b label: `b`,\n",
" b debug: `Err(1)`",
)
);
}

}

/// Assert expression is ok, and its value is equal to another.
///
/// * If true, return `()`.
///
/// * Otherwise, call [`panic!`] with a message and the values of the
/// expressions with their debug representations.
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate assertables;
/// # use std::panic;
/// # fn main() {
/// let a: Result<i8, i8> = Result::Ok(1);
/// let b: Result<i8, i8> = Result::Ok(1);
/// assert_result_ok_eq!(a, b);
/// //-> ()
///
/// // Panic with error message
/// let a: Result<i8, i8> = Result::Ok(1);
/// let b: Result<i8, i8> = Result::Ok(2);
/// let result = panic::catch_unwind(|| {
/// assert_result_ok_eq!(a, b);
/// //-> panic!
/// });
/// assert!(result.is_err());
/// let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
/// let expect = concat!(
/// "assertion failed: `assert_result_ok_eq!(a, b)`\n",
/// " a label: `a`,\n",
/// " a debug: `Ok(1)`,\n",
/// " b label: `b`,\n",
/// " b debug: `Ok(2)`,\n",
/// " a ok: `1`,\n",
/// " b ok: `2`",
/// );
/// assert_eq!(actual, expect);
///
/// // Panic with error message
/// let result = panic::catch_unwind(|| {
/// assert_result_ok_eq!(a, b, "message");
/// //-> panic!
/// });
/// assert!(result.is_err());
/// let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
/// let expect = "message";
/// assert_eq!(actual, expect);
/// # }
/// ```
///
/// # Module macros
///
/// * [`assert_result_ok_eq`](macro@crate::assert_result_ok_eq)
/// * [`assert_result_ok_eq_as_result`](macro@crate::assert_result_ok_eq_as_result)
/// * [`debug_assert_result_ok_eq`](macro@crate::debug_assert_result_ok_eq)
///
#[macro_export]
macro_rules! assert_result_ok_eq {
($a:expr, $b:expr $(,)?) => ({
match assert_result_ok_eq_as_result!($a, $b) {
Ok(()) => (),
Err(err) => panic!("{}", err),
}
});
($a:expr, $b:expr, $($message:tt)+) => ({
match assert_result_ok_eq_as_result!($a, $b) {
Ok(()) => (),
Err(_err) => panic!("{}", $($message)+),
}
});
}

/// Assert expression is ok, and its value is equal to another.
///
/// This macro provides the same statements as [`assert_result_ok_eq`](macro.assert_result_ok_eq.html),
/// except this macro's statements are only enabled in non-optimized
/// builds by default. An optimized build will not execute this macro's
/// statements unless `-C debug-assertions` is passed to the compiler.
///
/// This macro is useful for checks that are too expensive to be present
/// in a release build but may be helpful during development.
///
/// The result of expanding this macro is always type checked.
///
/// An unchecked assertion allows a program in an inconsistent state to
/// keep running, which might have unexpected consequences but does not
/// introduce unsafety as long as this only happens in safe code. The
/// performance cost of assertions, however, is not measurable in general.
/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
/// after thorough profiling, and more importantly, only in safe code!
///
/// This macro is intended to work in a similar way to
/// [`std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
///
/// # Module macros
///
/// * [`assert_result_ok_eq`](macro@crate::assert_result_ok_eq)
/// * [`assert_result_ok_eq`](macro@crate::assert_result_ok_eq)
/// * [`debug_assert_result_ok_eq`](macro@crate::debug_assert_result_ok_eq)
///
#[macro_export]
macro_rules! debug_assert_result_ok_eq {
($($arg:tt)*) => {
if $crate::cfg!(debug_assertions) {
$crate::assert_result_ok_eq!($($arg)*);
}
};
}
Loading

0 comments on commit dcba568

Please sign in to comment.