Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Features of `asserting`:
For an overview of the provided features and many examples on how to use `asserting` see the
[crate-level documentation][docs-url].

The assertion methods are mostly inspired by the [AssertJ] library for Java but adopted to Rust's
syntax and idioms.

To see what is changed with each release, see the [changelog](CHANGELOG.md).

### Convenient to write
Expand Down Expand Up @@ -70,7 +73,7 @@ Easy-to-extend means that we can write assertions for custom types with minimal
3. write custom assertions by implementing two simple traits (see "[custom assertions]")

The mentioned references link to a chapter in the crate's documentation that describes the
possibilities for custom assertions including examples.
possibilities for custom assertions, including examples.

## no-std support

Expand Down Expand Up @@ -414,18 +417,22 @@ for all iterators.
| contains_all_of | verify that an iterator/collection contains all the expected values in any order (and maybe more) |
| contains_only | verify that an iterator/collection contains only the specified values and nothing else in any order and ignoring duplicates |
| contains_only_once | verify that an iterator/collection contains only the specified values in any order and each of them only once |
| single_element | verify that an iterator/collection contains exaclty one element and return a `Spec` for that one element |
| filtered_on | filter the elements of an iterator/collection on a condition and return a `Spec` that contains the filtered elements |

for iterators that yield items in a well-defined order.

All the above assertions provided for any kind of iterator plus the following:

| assertion | description |
|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| contains_exactly | verify that an iterator/collection contains exactly the expected values and nothing else in the given order |
| contains_sequence | verify that an iterator/collection contains the given sequence of values in the given order and without extra values between the sequence values |
| contains_all_in_order | verify that an iterator/collection contains all the given values and in the given order, possibly with other values between them |
| starts_with | verify that an iterator/collection contains the given values as the first elements in order |
| ends_with | verify that an iterator/collection contains the given values as the last elements in order |
| first_element | verfiy that an iterator/collection contains at least one element and return a `Spec` containing the first element |
| last_element | verfiy that an iterator/collection contains at least one element and return a `Spec` containing the last element |
| nth_element | verfiy that an iterator/collection contains at least one element and return a `Spec` containing the nth element |
| elements_at | pick the elements of an iterator/collection at the given positions and return a `Spec` containing the selected elements |

### Maps

Expand Down Expand Up @@ -456,7 +463,7 @@ requires the crate feature `panic` which is enabled by default.
| panics | verify that some code panics |
| panics_with_message | verify that some code panics with the expected message |

To start assertions on code use the `assert_that_code!()` macro.
To start assertions on code, use the `assert_that_code!()` macro.

<!-- Badges and related URLs -->

Expand Down Expand Up @@ -497,3 +504,5 @@ To start assertions on code use the `assert_that_code!()` macro.
[`MapProperties`]: https://docs.rs/asserting/latest/asserting/properties/trait.MapProperties.html

[`NO_COLOR`]: https://no-color.org/

[AssertJ]: https://assertj.github.io/doc/
148 changes: 148 additions & 0 deletions src/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::spec::Spec;
use crate::std::fmt::Debug;
use crate::std::ops::RangeBounds;
use crate::std::string::String;
use crate::std::vec::Vec;

/// Assert whether two values are equal or not.
///
Expand Down Expand Up @@ -3651,3 +3652,150 @@ pub trait AssertMapContainsValue<E> {
#[track_caller]
fn does_not_contain_values(self, expected_values: impl IntoIterator<Item = E>) -> Self;
}

/// Filter assertions for elements of a collection or an iterator.
///
/// Filtering is used to target the assertions on specific elements of a
/// collection or an iterator, such as a single element or elements matching a
/// condition.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["single"];
/// assert_that!(subject).single_element().is_equal_to("single");
///
/// let subject = [1, 2, 3, 4, 5];
/// assert_that!(subject).filtered_on(|e| e & 1 == 0).contains_exactly_in_any_order([2, 4]);
/// ```
pub trait AssertElements<'a, T, R> {
/// Verify that the iterator contains exactly one element and return a
/// [`Spec`] for that single element.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["single"];
///
/// assert_that!(subject).single_element().is_equal_to("single");
/// ```
#[track_caller]
fn single_element(self) -> Spec<'a, T, R>;

/// Filter the elements of a collection or an iterator on a condition and
/// return a [`Spec`] only containing the elements that match the condition.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = [1, 2, 3, 4, 5];
/// assert_that!(subject)
/// .filtered_on(|e| e & 1 == 0)
/// .contains_exactly_in_any_order([2, 4]);
///
/// let subject = ["one", "two", "three", "four"];
/// assert_that!(subject)
/// .filtered_on(|e| e.len() == 5)
/// .single_element()
/// .is_equal_to("three");
/// ```
#[track_caller]
fn filtered_on(self, condition: impl Fn(&T) -> bool) -> Spec<'a, Vec<T>, R>;
}

/// Filter assertions for elements of a collection or an iterator that yields
/// its elements in a defined order.
///
/// Filtering is used to target the assertions on specific elements of a
/// collection or an iterator, such as the first or last element.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["first", "second", "third", "four", "five"];
///
/// assert_that!(subject).first_element().is_equal_to("first");
/// assert_that!(subject).last_element().is_equal_to("five");
/// assert_that!(subject).nth_element(3).is_equal_to("four");
///
/// let subject = ["one", "two", "three", "four", "five"];
///
/// assert_that!(subject)
/// .elements_at([0, 2, 4])
/// .contains_exactly(["one", "three", "five"]);
/// ```
pub trait AssertOrderedElements<'a, T, R> {
/// Verify that a collection or an iterator contains at least one element
/// and return a [`Spec`] for the first element.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["first", "second", "third"];
///
/// assert_that!(subject).first_element().is_equal_to("first");
/// ```
#[track_caller]
fn first_element(self) -> Spec<'a, T, R>;

/// Verify that a collection or an iterator contains at least one element
/// and return a [`Spec`] for the last element.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["first", "second", "third"];
///
/// assert_that!(subject).last_element().is_equal_to("third");
/// ```
#[track_caller]
fn last_element(self) -> Spec<'a, T, R>;

/// Verify that a collection or an iterator contains at least n + 1 elements
/// and return a [`Spec`] for the nth element.
///
/// The index n is zero-based (similar to the `nth` method of iterators).
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["first", "second", "third"];
///
/// assert_that!(subject).nth_element(0).is_equal_to("first");
/// assert_that!(subject).nth_element(1).is_equal_to("second");
/// assert_that!(subject).nth_element(2).is_equal_to("third");
/// ```
#[track_caller]
fn nth_element(self, n: usize) -> Spec<'a, T, R>;

/// Pick the elements of a collection or an iterator at the given positions
/// and return a [`Spec`] only containing the selected elements.
///
/// # Examples
///
/// ```
/// use asserting::prelude::*;
///
/// let subject = ["one", "two", "three", "four", "five"];
///
/// assert_that!(subject)
/// .elements_at([0, 2, 4])
/// .contains_exactly(["one", "three", "five"]);
/// ```
#[track_caller]
fn elements_at(self, indices: impl IntoIterator<Item = usize>) -> Spec<'a, Vec<T>, R>;
}
20 changes: 20 additions & 0 deletions src/expectations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,26 @@ impl<E> IteratorEndsWith<E> {
}
}

pub fn has_single_element() -> HasSingleElement {
HasSingleElement
}

#[must_use]
pub struct HasSingleElement;

pub fn has_at_least_number_of_elements(
expected_number_of_elements: usize,
) -> HasAtLeastNumberOfElements {
HasAtLeastNumberOfElements {
expected_number_of_elements,
}
}

#[must_use]
pub struct HasAtLeastNumberOfElements {
pub expected_number_of_elements: usize,
}

/// Creates a [`MapContainsKey`] expectation.
pub fn map_contains_key<E>(expected_key: E) -> MapContainsKey<E> {
MapContainsKey { expected_key }
Expand Down
Loading
Loading