assert-rs 0.1.0

An assertion library that uses types and data to fail tests instead of panicking.
Documentation
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`:

```no_run
#[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:

```no_run
#[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:

```no_run
#[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),
    )
}
```

```text
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:

```no_run
#[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.