Skip to main content

Crate assert_rs

Crate assert_rs 

Source
Expand description

An assertion library that uses types and data to fail tests instead of panicking.

I made this crate for a project I’m working on that’s #[no_std], has no allocator, uses a custom-built test framework, and has no support for unwinding. Assertions that panic are therefore undesirable, since panicking exits the test handler and will prevent further tests from running.

That said, this library still works for crates that use the standard test framework. Instead of returning () from tests, simply return impl Assertion:

#[test]
fn is_equal_to() -> impl Assertion {
    assert_that!(1 + 2).is_equal_to(3)
}

and the test framework will use the std::process::Termination implementation on Assertion to determine success or failure. The assert_that! macro also captures the exact location of its invocation, so error messages can still be descriptive.

There is also multi_assert!, which allows you to test multiple assertions at once:

#[test]
fn multi_assert() -> impl Assertion {
    multi_assert!(
        assert_that!(1 + 2).is_equal_to(3),
        assert_that!(3 + 4).is_equal_to(7),
        assert_that!(23).is_equal_to(10 * 2 + 3),
        assert_that!(7).is_greater_than(5),
        assert_that!(42).is_not_equal_to(6),
    )
}

Multi-assertions are not short-circuiting, so failed assertions will print all their errors:

#[test]
fn multi_assert_fail_messages() -> impl Assertion {
    multi_assert!(
        assert_that!(1 + 1).is_equal_to(2),
        assert_that!(1 + 2).is_equal_to(2),
        assert_that!(1 + 2).is_equal_to(4),
        assert_that!(3 + 4).is_equal_to(7),
        assert_that!(9 + 10).is_greater_than(23),
    )
}
assertion failures in a multi-assert:
0. [ok]
1. assertion starting at src/tests/multi.rs:42:9 failed: `lhs == rhs`
 lhs: 3
 rhs: 2

2. assertion starting at src/tests/multi.rs:43:9 failed: `lhs == rhs`
 lhs: 3
 rhs: 4

3. [ok]
4. assertion starting at src/tests/multi.rs:45:9 failed: `lhs > rhs`
 lhs: 19
 rhs: 23

You can even use assertions of different types in multi-assertions using the #[dyn] attribute:

#[test]
fn multi_assert_dyn() -> impl Assertion {
    multi_assert!(#[dyn] // <- casts assertions to `dyn Assertion`
        assert_that!(1 + 2).is_equal_to(3), // <- BinaryAssertion<i32, i32>
        assert_that!(true).is_true(), // <- UnaryAssertion<bool>
        assert_that!(true).is_false().should_fail(), // <- ShouldFail<UnaryAssertion<bool>>
    )
}

§Feature flags

Support for std (and alloc) is provided by default, but these can be disabled with the std and alloc feature flags (where std implies alloc).

  • Disabling std removes the std::process::Termination requirement and implementations for Assertion. It will not be possible to return impl Assertion from tests without this flag, however if you’re using a custom test framework you should be able to build around this.
  • Disabling alloc will remove the ability to use the #[dyn] attribute in multi_assert!, as it requires Box to work.

Re-exports§

pub use assertion::AssertAll;
pub use assertion::Assertion;

Modules§

assertion

Macros§

assert_that
Construct the first part of an Assertion.
fail
Construct an Assertion that will always fail.
multi_assert
Construct a group of assertions that will all be tested simultaneously. If one assertion fails, the group as a whole will fail.
succeed
Construct an Assertion that will always succeed.

Structs§

Assert
A wrapper around some object that can be reasoned about.
AssertInfo
Information about an invocation of assert_that!.