Crate kernal

Source
Expand description

Kernal allows you to use fluent assertions in Rust tests. That is, instead of writing assert_eq!(my_vec.len(), 10), you can write assert_that!(my_vec).has_length(10), making your tests more readable and enabling the framework to provide more expressive error messages. Kernal aims to provide specialized assertions for as many commonly tested properties as possible.

§Writing an assertion

When you write an assertion over a value, you always start withassert_that!(<your value>). The assert_that macro gives you an instance on which you can call associated functions to make your assertions. To be able to use these assertions, the specialized extension traits must be imported, such as StringAssertions when using special assertions for Strings. You can glob-import the prelude module to get all imports you need to write every assertion supported by Kernal.

use kernal::prelude::*;

assert_that!("hello world").contains("world");

§Chaining

Every assertion returns the same asserter instance to continue writing assertions on the same value. In addition, some extension traits define mapping methods that manipulate the data in some way and return asserter instances on the new data.

use kernal::prelude::*;

assert_that!("almost")
    .has_char_length(6)
    .ends_with("most")
    .to_chars()
    .is_sorted_in_strictly_ascending_order();

§Creating custom assertions

kernal allows the creation of custom assertions to test instances of your types in a more natural way. To do this, create a new trait which has a method for your assertion. This will be called on the output of the assert_that macro. In order to enable its usage, you need to implement your trait on the AssertThat with the type you want to test as a type parameter. Import the AssertThatData trait to get access to the tested data. It is not provided in the prelude module in order to avoid presenting these methods every time the user looks for an assertion. You can use the Failure struct to compose an error message consistent with the kernal crate. The example below demonstrates this process.

use kernal::{AssertThat, AssertThatData, Failure};
use kernal::prelude::*;

// Our type for which we want to write assertions.
struct Vector2f32 { x: f32, y: f32 }

// The custom assertion trait we will later implement on `AssertThat`.
trait Vector2f32Assertions {
    // The custom assertion we want to supply. It is recommended to take an owned `self` and
    // return the same instance to support chaining.
    fn has_euclidean_norm(self, expected_norm: f32, epsilon: f32) -> AssertThat<Vector2f32>;
}

impl Vector2f32Assertions for AssertThat<Vector2f32> {
    fn has_euclidean_norm(self, expected_norm: f32, epsilon: f32) -> AssertThat<Vector2f32> {
        // We get our data with `self.data()`, supplied by `AssertThatData`
        let vector = self.data();
        let actual_norm = (vector.x * vector.x + vector.y * vector.y).sqrt();

        if (actual_norm - expected_norm).abs() > epsilon {
            // Here we must fail - using the `Failure` struct
            Failure::new(&self)
                .expected_it(format!("to have a euclidean norm within <{}> of <{}>",
                    epsilon, expected_norm))
                .but_it(format!("was <({}, {})>, with a euclidean norm of <{}>",
                    vector.x, vector.y, actual_norm))
                .fail()
        }

        // Here the test passes, so we return `self` for chaining
        self
    }
}

assert_that!(Vector2f32 { x: 3.0, y: 4.0 }).has_euclidean_norm(5.0, 0.01);
assert_that!(|| assert_that!(Vector2f32 { x: 3.0, y: 3.0 }).has_euclidean_norm(5.0, 0.01))
    .panics();

§Notes on performance

Should you write assertions on large amounts of data, the standard assertions may become a bottleneck. For some use cases, there are specialized assertions that use additional trait bounds to improve performance. These are available under the fast_prelude module. See below for an example on how to use it.

use kernal::prelude::*;
use kernal::fast_prelude::*;

assert_that!([1, 2, 3, 4, 5])
    .contains_all_of_using_hash([2, 3, 4])
    .contains_none_of_using_ord([6, 7, 8]);

If no sufficiently performant assertion is available, you should consider falling back to standard assertions.

Modules§

abs_diff
Contains assertions for values whose distance to each other can be measured, to check whether values are close. Such types are grouped by the AbsDiff trait. See AbsDiffPartialOrdAssertions for more details.
boolean
Contains assertions for bool values. See the BooleanAssertions trait for more details.
character
Contains assertions for char values. See the CharacterAssertions trait for more details.
collections
Defines the basic Collection trait to generalize collections such as sets and lists. Additional assertions for collections are provided by CollectionAssertions. Sub-modules provide further specialization.
error
Contains assertions for types which implement Error. See the ErrorAssertions trait for more details.
fast_prelude
This module re-exports all assertion traits which have specialized implementations of other assertions with additional trait bounds, but better performance. This means that by glob-importing this and prelude, all assertion methods become available.
lock
Contains assertions for standard library lock types. These are additionally grouped by the Lock trait used to check whether locks are poisoned in LockAssertions. Furthermore, specialized assertions are provided by the MutexAssertions and RwLockAssertions traits.
maps
Defines the basic Map to generalize all types of maps (such as hash maps) and defines wrapper structs to create Collection views of a map. In addition, general map-based assertions are provided by MapAssertions. Sub-modules of this module provide more specialized assertions.
num
Defines basic numeric traits implemented on appropriate primitive types. Sub-modules contain assertions for numeric types implementing these traits.
option
Contains assertions for Option values. The OptionAssertions works for all Options which implement Debug. OptionPartialEqAssertions provides additional assertions if the value type implements PartialEq.
panic
Contains assertions to test potentially panicking functions. See PanicAssertions for more details.
partial_eq
Contains assertions for values which implement PartialEq. See PartialEqAssertions for more details.
partial_ord
Contains assertions for values which implement PartialOrd. See PartialOrdAssertions for more details.
path
Contains assertions for Paths. See PathAssertions for more details.
pointer
Contains assertions for pointers, which are grouped by the Pointer trait. See PointerAssertions for more details.
prelude
This module re-exports the assert_that macro as well as all assertion traits implemented by some results of that macro, except performance-optimized ones (see fast_prelude). This means that by glob-importing this module all functionally distinguishable assertion methods become available.
result
Contains assertions for Result values. The ResultAssertions works for all Results which implement Debug. ResultValuePartialEqAssertions provides additional assertions if the value type implements PartialEq and ResultErrorPartialEqAssertions if the error type implements PartialEq.
string
Contains assertions for string values, including among others String and references to str. See StringAssertions for more details.

Macros§

assert_that
This macro starts every assertion. It takes an expression and returns an AssertThat instance which allows to perform various assertions on the value generated by the expression. Remember to import prelude in order to get access to all assertions. That import also provides this macro.
dyn_assertions
A utility macro for constructing slices of assertion trait objects, that is, boxed functions which take some input and have no output. These are used as input to assertions which distribute items over assertions, such as OrderedCollectionAssertions::satisfies_exactly_in_given_order. It accepts patterns in the form of a list of lambda expressions, ignores the output of each one and wraps it in a box.

Structs§

AssertThat
This struct holds the evaluated result of an expression for further assertions. It also contains metadata used for generating helpful error messages should an assertion fail.
Failure
This type is used to generate error messages of a specific format. It is mostly used internally, but exported to enable users to extend the assertions provided by this crate for custom types.

Traits§

AssertThatData
This trait provides access to the tested data of an AssertThat to write custom assertions.