assert-rs 0.1.1

An assertion library that uses types and data to fail tests instead of panicking.
Documentation
  • Coverage
  • 96.55%
    56 out of 58 items documented5 out of 46 items with examples
  • Size
  • Source code size: 54.03 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.11 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 6s Average build duration of successful builds.
  • all releases: 4s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • JT992/assert-rs
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • JT992

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.