1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
// SPDX-FileCopyrightText: 2024 Markus Haug (Korrat)
//
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! This crate provides helpers for working with Nullables as described by James Shore in [Testing without Mocks].
//!
//! [Testing without Mocks]: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks
extern crate alloc;
pub use nullable_utils_macros::*;
pub use crate::output::Listener as OutputListener;
pub use crate::output::Tracker as OutputTracker;
mod output;
/// `NulledResponses` helps with implementing [Configurable Responses] for Nullable types.
///
/// [Configurable Responses]: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#configurable-responses
#[derive(Clone, Debug)]
// TODO exchange this for an implementation using boxed iterators?
pub enum NulledResponses<T> {
/// Repeat a single response forever.
Repeating(T),
/// Return a sequence of responses, panicking when the sequence runs out.
Sequence(alloc::vec::Vec<T>),
}
impl<T> NulledResponses<T> {
/// Backmap can be used to convert between `NulledResponses` for different types.
///
/// For example, a high-level infrastructure wrapper can use this to convert its own response configuration into a
/// response configuration for an embedded lower-level infrastructure wrapper.
pub fn backmap<U>(self, mut mapper: impl FnMut(T) -> U) -> NulledResponses<U> {
match self {
Self::Repeating(response) => NulledResponses::Repeating(mapper(response)),
Self::Sequence(responses) => {
NulledResponses::Sequence(responses.into_iter().map(mapper).collect())
}
}
}
}
impl<T> NulledResponses<T>
where
T: Clone,
{
/// Gets the next response.
///
/// # Panics
///
/// Panics if this object was configured with a finite sequence of responses and that sequence has been exhausted.
pub fn get(&mut self) -> T {
match self {
Self::Repeating(response) => response.clone(),
Self::Sequence(responses) => responses.pop().expect("not enough responses configured"),
}
}
}
impl<T, const N: usize> From<[T; N]> for NulledResponses<T> {
fn from(value: [T; N]) -> Self {
Self::from(Vec::from(value))
}
}
impl<T> From<&[T]> for NulledResponses<T>
where
T: Clone,
{
fn from(value: &[T]) -> Self {
Self::from(Vec::from(value))
}
}
impl<T> From<T> for NulledResponses<T>
where
T: Clone,
{
fn from(value: T) -> Self {
Self::Repeating(value)
}
}
impl<T> From<Vec<T>> for NulledResponses<T> {
fn from(mut value: Vec<T>) -> Self {
value.reverse();
Self::Sequence(value)
}
}