Struct mimicry::Answers

source ·
pub struct Answers<V, Ctx = ()> { /* private fields */ }
Expand description

Answers for a function call.

Answers are similar to an Iterator, but with some additional functionality:

  • Response can be based on a certain context (the second type param) provided to Self::next_for().
  • The provided contexts are recorded for each call and then can be retrieved using Self::take_calls(). This can be used to verify calls.

The intended usage of Answers is as an element of Mock state used in one or more mock methods.

Examples

let mut answers: Answers<usize> = Answers::from_values([1, 3, 5]);
let value: usize = answers.next_for(());
assert_eq!(value, 1);
assert_eq!(answers.next_for(()), 3);
assert_eq!(answers.take_calls().len(), 2);

Context-dependent Answers:

let mut counter = 0;
let mut answers = Answers::from_fn(move |s: &String| {
    if counter == 0 && s == "test" {
        counter += 1;
        42
    } else {
        s.len()
    }
});
assert_eq!(answers.next_for("test".into()), 42);
assert_eq!(answers.next_for("??".into()), 2);
assert_eq!(answers.next_for("test".into()), 4);

let calls = answers.take_calls();
assert_eq!(calls, ["test", "??", "test"]);

Channels

Basic usage of Answers::channel():

use mimicry::Answers;

let (mut answers, mut sx) = Answers::channel();
// `rx` can be placed in the mock state
sx.send(42).scope(|| {
    // Realistically, here you would call something that uses
    // the mock, possibly with indirection.
    assert_eq!(answers.next_for(()), 42);
});

Async scope wrapper is also available:

let (mut answers, mut sx) = Answers::channel();
let future = sx.send(42).async_scope(async {
    assert_eq!(answers.next_for(()), 42);
});
future.await;

More advanced usage with explicit guard handling:

let (mut answers, mut sx) = Answers::channel();
let guard: AnswersGuard<_> = sx.send_all([0, 1, 2, 0, 1]);
for i in 0..4 {
    assert_eq!(answers.next_for(i), i % 3);
}
guard.discard(); // ignore the remaining answer

If not all answers were used when a guard is dropped, it panics:

let (mut answers, mut sx) = Answers::channel();
sx.send_all([0, 1]).scope(|| {
    assert_eq!(answers.next_for(()), 0);
    // The code under test should make another call to the mock,
    // but it does not.
});

Functional values

To deal with more complex cases, Answers can contain functional values.

#[mock(using = "SimpleMock::mock_fn")]
fn tested_fn(s: &str, start: usize) -> &str {
    &s[start..]
}

type StrFn = fn(&str) -> &str;

#[derive(Mock)]
#[mock(mut)]
struct SimpleMock {
    str_fns: Answers<StrFn, (String, usize)>,
}

impl SimpleMock {
    fn mock_fn<'s>(this: &Mut<Self>, s: &'s str, start: usize) -> &'s str {
        let context = (s.to_owned(), start);
        let str_fn = this.borrow().str_fns.next_for(context);
        str_fn(s)
    }
}

// Setup mock with 2 functions.
let return_test: StrFn = |_| "test";
let suffix: StrFn = |s| &s[1..];
let mock = SimpleMock {
    str_fns: Answers::from_values([return_test, suffix]),
};
let guard = mock.set_as_mock();

// Perform some tests.
assert_eq!(tested_fn("first", 0), "test");
assert_eq!(tested_fn("second", 3), "econd");

// Verify mock calls.
let calls = guard.into_inner().str_fns.take_calls();
assert_eq!(calls.len(), 2);
assert_eq!(calls[0].0, "first");
assert_eq!(calls[1].1, 3);

Implementations

Answers based on the provided function.

Answers with values from the provided iterator. Once the iterator runs out of items, panics.

Selects an answer based on the specified context. The context is recorded and can then be retrieved via Self::take_calls().

Takes contexts for recorded calls since the last call to Self::take_calls(), or after creation if called for the first time.

Answers with the provided value once. Further calls will panic.

Creates a new Answers instance that can receive answers dynamically via a channel. The channel functions similar to a blocking channel from the standard library.

Unlike with Self::from_value() / Self::from_values(), using a channel allows building answers dynamically after the mock is already set up.

Answers with the provided value infinite number of times.

Trait Implementations

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.